Merge pull request #1564 from ghalestrilo/feature/switch-mobile-desktop
Feature/switch mobile desktop
This commit is contained in:
commit
d126821301
18 changed files with 153 additions and 124 deletions
|
@ -91,7 +91,8 @@ Dropdown.propTypes = {
|
||||||
items: PropTypes.arrayOf(PropTypes.shape({
|
items: PropTypes.arrayOf(PropTypes.shape({
|
||||||
action: PropTypes.func,
|
action: PropTypes.func,
|
||||||
icon: PropTypes.func,
|
icon: PropTypes.func,
|
||||||
href: PropTypes.string
|
href: PropTypes.string,
|
||||||
|
title: PropTypes.string
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,7 @@ export const COLLAPSE_CONSOLE = 'COLLAPSE_CONSOLE';
|
||||||
|
|
||||||
export const UPDATE_LINT_MESSAGE = 'UPDATE_LINT_MESSAGE';
|
export const UPDATE_LINT_MESSAGE = 'UPDATE_LINT_MESSAGE';
|
||||||
export const CLEAR_LINT_MESSAGE = 'CLEAR_LINT_MESSAGE';
|
export const CLEAR_LINT_MESSAGE = 'CLEAR_LINT_MESSAGE';
|
||||||
|
export const TOGGLE_FORCE_DESKTOP = 'TOGGLE_FORCE_DESKTOP';
|
||||||
|
|
||||||
export const UPDATE_FILE_NAME = 'UPDATE_FILE_NAME';
|
export const UPDATE_FILE_NAME = 'UPDATE_FILE_NAME';
|
||||||
export const DELETE_FILE = 'DELETE_FILE';
|
export const DELETE_FILE = 'DELETE_FILE';
|
||||||
|
|
|
@ -14,3 +14,9 @@ export function clearLintMessage() {
|
||||||
type: ActionTypes.CLEAR_LINT_MESSAGE
|
type: ActionTypes.CLEAR_LINT_MESSAGE
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function toggleForceDesktop() {
|
||||||
|
return {
|
||||||
|
type: ActionTypes.TOGGLE_FORCE_DESKTOP
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -263,8 +263,6 @@ class SketchListRowBase extends React.Component {
|
||||||
url = `/${username}/sketches/${slugify(sketch.name, '_')}`;
|
url = `/${username}/sketches/${slugify(sketch.name, '_')}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.props.mobile) url = `/mobile${url}`;
|
|
||||||
|
|
||||||
const name = (
|
const name = (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Link to={url}>
|
<Link to={url}>
|
||||||
|
|
|
@ -63,19 +63,19 @@ const NavItem = styled.li`
|
||||||
position: relative;
|
position: relative;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const getNavOptions = (username = undefined, logoutUser = () => {}) =>
|
const getNavOptions = (username = undefined, logoutUser = () => {}, toggleForceDesktop = () => {}) =>
|
||||||
(username
|
(username
|
||||||
? [
|
? [
|
||||||
{ icon: PreferencesIcon, title: 'Preferences', href: '/mobile/preferences', },
|
{ icon: PreferencesIcon, title: 'Preferences', href: '/preferences', },
|
||||||
{ icon: PreferencesIcon, title: 'My Stuff', href: `/mobile/${username}/sketches` },
|
{ icon: PreferencesIcon, title: 'My Stuff', href: `/${username}/sketches` },
|
||||||
{ icon: PreferencesIcon, title: 'Examples', href: '/mobile/p5/sketches' },
|
{ icon: PreferencesIcon, title: 'Examples', href: '/p5/sketches' },
|
||||||
{ icon: PreferencesIcon, title: 'Original Editor', href: '/', },
|
{ icon: PreferencesIcon, title: 'Original Editor', action: toggleForceDesktop, },
|
||||||
{ icon: PreferencesIcon, title: 'Logout', action: logoutUser, },
|
{ icon: PreferencesIcon, title: 'Logout', action: logoutUser, },
|
||||||
]
|
]
|
||||||
: [
|
: [
|
||||||
{ icon: PreferencesIcon, title: 'Preferences', href: '/mobile/preferences', },
|
{ icon: PreferencesIcon, title: 'Preferences', href: '/preferences', },
|
||||||
{ icon: PreferencesIcon, title: 'Examples', href: '/mobile/p5/sketches' },
|
{ icon: PreferencesIcon, title: 'Examples', href: '/p5/sketches' },
|
||||||
{ icon: PreferencesIcon, title: 'Original Editor', href: '/', },
|
{ icon: PreferencesIcon, title: 'Original Editor', action: toggleForceDesktop, },
|
||||||
{ icon: PreferencesIcon, title: 'Login', href: '/login', },
|
{ icon: PreferencesIcon, title: 'Login', href: '/login', },
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
@ -86,7 +86,8 @@ const MobileIDEView = (props) => {
|
||||||
selectedFile, updateFileContent, files, user, params,
|
selectedFile, updateFileContent, files, user, params,
|
||||||
closeEditorOptions, showEditorOptions, logoutUser,
|
closeEditorOptions, showEditorOptions, logoutUser,
|
||||||
startRefreshSketch, stopSketch, expandSidebar, collapseSidebar, clearConsole, console,
|
startRefreshSketch, stopSketch, expandSidebar, collapseSidebar, clearConsole, console,
|
||||||
showRuntimeErrorWarning, hideRuntimeErrorWarning, startSketch, getProject, clearPersistedState, setUnsavedChanges
|
showRuntimeErrorWarning, hideRuntimeErrorWarning, startSketch, getProject, clearPersistedState, setUnsavedChanges,
|
||||||
|
toggleForceDesktop
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const [tmController, setTmController] = useState(null); // eslint-disable-line
|
const [tmController, setTmController] = useState(null); // eslint-disable-line
|
||||||
|
@ -112,7 +113,7 @@ const MobileIDEView = (props) => {
|
||||||
|
|
||||||
// Screen Modals
|
// Screen Modals
|
||||||
const [toggleNavDropdown, NavDropDown] = useAsModal(<Dropdown
|
const [toggleNavDropdown, NavDropDown] = useAsModal(<Dropdown
|
||||||
items={getNavOptions(username, logoutUser)}
|
items={getNavOptions(username, logoutUser, toggleForceDesktop)}
|
||||||
align="right"
|
align="right"
|
||||||
/>);
|
/>);
|
||||||
|
|
||||||
|
@ -131,6 +132,7 @@ const MobileIDEView = (props) => {
|
||||||
subtitle={selectedFile.name}
|
subtitle={selectedFile.name}
|
||||||
>
|
>
|
||||||
<NavItem>
|
<NavItem>
|
||||||
|
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={toggleNavDropdown}
|
onClick={toggleNavDropdown}
|
||||||
icon={MoreIcon}
|
icon={MoreIcon}
|
||||||
|
@ -139,7 +141,7 @@ const MobileIDEView = (props) => {
|
||||||
<NavDropDown />
|
<NavDropDown />
|
||||||
</NavItem>
|
</NavItem>
|
||||||
<li>
|
<li>
|
||||||
<IconButton to="/mobile/preview" onClick={() => { startSketch(); }} icon={PlayIcon} aria-label="Run sketch" />
|
<IconButton to="/preview" onClick={() => { startSketch(); }} icon={PlayIcon} aria-label="Run sketch" />
|
||||||
</li>
|
</li>
|
||||||
</Header>
|
</Header>
|
||||||
|
|
||||||
|
@ -289,6 +291,7 @@ MobileIDEView.propTypes = {
|
||||||
showRuntimeErrorWarning: PropTypes.func.isRequired,
|
showRuntimeErrorWarning: PropTypes.func.isRequired,
|
||||||
|
|
||||||
hideRuntimeErrorWarning: PropTypes.func.isRequired,
|
hideRuntimeErrorWarning: PropTypes.func.isRequired,
|
||||||
|
toggleForceDesktop: PropTypes.func.isRequired,
|
||||||
|
|
||||||
user: PropTypes.shape({
|
user: PropTypes.shape({
|
||||||
authenticated: PropTypes.bool.isRequired,
|
authenticated: PropTypes.bool.isRequired,
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import * as ActionTypes from '../../../constants';
|
import * as ActionTypes from '../../../constants';
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
lintMessages: []
|
lintMessages: [],
|
||||||
|
forceDesktop: false
|
||||||
};
|
};
|
||||||
let messageId = 0;
|
let messageId = 0;
|
||||||
|
|
||||||
|
@ -16,6 +17,8 @@ const editorAccessibility = (state = initialState, action) => {
|
||||||
});
|
});
|
||||||
case ActionTypes.CLEAR_LINT_MESSAGE:
|
case ActionTypes.CLEAR_LINT_MESSAGE:
|
||||||
return Object.assign({}, state, { lintMessages: [] });
|
return Object.assign({}, state, { lintMessages: [] });
|
||||||
|
case ActionTypes.TOGGLE_FORCE_DESKTOP:
|
||||||
|
return Object.assign({}, state, { forceDesktop: !(state.forceDesktop) });
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,8 +138,8 @@ const Panels = {
|
||||||
|
|
||||||
|
|
||||||
const navOptions = username => [
|
const navOptions = username => [
|
||||||
{ title: 'Create Sketch', href: '/mobile' },
|
{ title: 'Create Sketch', href: '/' },
|
||||||
{ title: 'Create Collection', href: `/mobile/${username}/collections/create` }
|
{ title: 'Create Collection', href: `/${username}/collections/create` }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
@ -185,7 +185,7 @@ const MobileDashboard = ({ params, location }) => {
|
||||||
<NavDropdown />
|
<NavDropdown />
|
||||||
|
|
||||||
</NavItem>
|
</NavItem>
|
||||||
<IconButton to="/mobile" icon={ExitIcon} aria-label="Return to ide view" />
|
<IconButton to="/" icon={ExitIcon} aria-label="Return to ide view" />
|
||||||
</Header>
|
</Header>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ const MobilePreferences = () => {
|
||||||
<Screen fullscreen>
|
<Screen fullscreen>
|
||||||
<section>
|
<section>
|
||||||
<Header transparent title="Preferences">
|
<Header transparent title="Preferences">
|
||||||
<IconButton to="/mobile" icon={ExitIcon} aria-label="Return to ide view" />
|
<IconButton to="/" icon={ExitIcon} aria-label="Return to ide view" />
|
||||||
</Header>
|
</Header>
|
||||||
<section className="preferences">
|
<section className="preferences">
|
||||||
<Content>
|
<Content>
|
||||||
|
|
|
@ -39,7 +39,7 @@ const MobileSketchView = () => {
|
||||||
return (
|
return (
|
||||||
<Screen fullscreen>
|
<Screen fullscreen>
|
||||||
<Header
|
<Header
|
||||||
leftButton={<IconButton to="/mobile" icon={ExitIcon} aria-label="Return to original editor" />}
|
leftButton={<IconButton to="/" icon={ExitIcon} aria-label="Return to original editor" />}
|
||||||
title={projectName}
|
title={projectName}
|
||||||
/>
|
/>
|
||||||
<Content>
|
<Content>
|
||||||
|
|
|
@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
|
||||||
import { remSize } from '../../../theme';
|
import { remSize } from '../../../theme';
|
||||||
|
|
||||||
|
|
||||||
const ResponsiveFormWrapper = styled.div`
|
const ResponsiveForm = styled.div`
|
||||||
.form-container__content {
|
.form-container__content {
|
||||||
width: unset !important;
|
width: unset !important;
|
||||||
padding-top: ${remSize(16)};
|
padding-top: ${remSize(16)};
|
||||||
|
@ -42,23 +42,4 @@ const ResponsiveFormWrapper = styled.div`
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ResponsiveForm = props =>
|
|
||||||
(props.mobile === true
|
|
||||||
? (
|
|
||||||
<ResponsiveFormWrapper>
|
|
||||||
{props.children}
|
|
||||||
</ResponsiveFormWrapper>
|
|
||||||
|
|
||||||
)
|
|
||||||
: props.children);
|
|
||||||
|
|
||||||
ResponsiveForm.propTypes = {
|
|
||||||
mobile: PropTypes.bool,
|
|
||||||
children: PropTypes.oneOfType([PropTypes.node, PropTypes.array]),
|
|
||||||
};
|
|
||||||
ResponsiveForm.defaultProps = {
|
|
||||||
mobile: false,
|
|
||||||
children: []
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ResponsiveForm;
|
export default ResponsiveForm;
|
||||||
|
|
|
@ -28,40 +28,36 @@ class LoginView extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const isMobile = () => (window.innerWidth < 770);
|
|
||||||
if (this.props.user.authenticated) {
|
if (this.props.user.authenticated) {
|
||||||
this.gotoHomePage();
|
this.gotoHomePage();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// TODO: mobile currently forced to true
|
|
||||||
return (
|
return (
|
||||||
<ResponsiveForm mobile={isMobile() || this.props.mobile}>
|
<div className="login">
|
||||||
<div className="login">
|
<Nav layout="dashboard" />
|
||||||
<Nav layout="dashboard" />
|
<main className="form-container">
|
||||||
<main className="form-container">
|
<Helmet>
|
||||||
<Helmet>
|
<title>{this.props.t('LoginView.Title')}</title>
|
||||||
<title>{this.props.t('LoginView.Title')}</title>
|
</Helmet>
|
||||||
</Helmet>
|
<div className="form-container__content">
|
||||||
<div className="form-container__content">
|
<h2 className="form-container__title">{this.props.t('LoginView.Login')}</h2>
|
||||||
<h2 className="form-container__title">{this.props.t('LoginView.Login')}</h2>
|
<LoginForm {...this.props} />
|
||||||
<LoginForm {...this.props} />
|
<h2 className="form-container__divider">{this.props.t('LoginView.LoginOr')}</h2>
|
||||||
<h2 className="form-container__divider">{this.props.t('LoginView.LoginOr')}</h2>
|
<div className="form-container__stack">
|
||||||
<div className="form-container__stack">
|
<SocialAuthButton service={SocialAuthButton.services.github} />
|
||||||
<SocialAuthButton service={SocialAuthButton.services.github} />
|
<SocialAuthButton service={SocialAuthButton.services.google} />
|
||||||
<SocialAuthButton service={SocialAuthButton.services.google} />
|
|
||||||
</div>
|
|
||||||
<p className="form__navigation-options">
|
|
||||||
{this.props.t('LoginView.DontHaveAccount')}
|
|
||||||
<Link className="form__signup-button" to="/signup">{this.props.t('LoginView.SignUp')}</Link>
|
|
||||||
</p>
|
|
||||||
<p className="form__navigation-options">
|
|
||||||
{this.props.t('LoginView.ForgotPassword')}
|
|
||||||
<Link className="form__reset-password-button" to="/reset-password"> {this.props.t('LoginView.ResetPassword')}</Link>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</main>
|
<p className="form__navigation-options">
|
||||||
</div>
|
{this.props.t('LoginView.DontHaveAccount')}
|
||||||
</ResponsiveForm>
|
<Link className="form__signup-button" to="/signup">{this.props.t('LoginView.SignUp')}</Link>
|
||||||
|
</p>
|
||||||
|
<p className="form__navigation-options">
|
||||||
|
{this.props.t('LoginView.ForgotPassword')}
|
||||||
|
<Link className="form__reset-password-button" to="/reset-password"> {this.props.t('LoginView.ResetPassword')}</Link>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,14 +81,12 @@ LoginView.propTypes = {
|
||||||
authenticated: PropTypes.bool
|
authenticated: PropTypes.bool
|
||||||
}),
|
}),
|
||||||
t: PropTypes.func.isRequired,
|
t: PropTypes.func.isRequired,
|
||||||
mobile: PropTypes.bool
|
|
||||||
};
|
};
|
||||||
|
|
||||||
LoginView.defaultProps = {
|
LoginView.defaultProps = {
|
||||||
user: {
|
user: {
|
||||||
authenticated: false
|
authenticated: false
|
||||||
},
|
},
|
||||||
mobile: false
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default withTranslation()(reduxForm({
|
export default withTranslation()(reduxForm({
|
||||||
|
|
|
@ -13,7 +13,6 @@ import SocialAuthButton from '../components/SocialAuthButton';
|
||||||
import Nav from '../../../components/Nav';
|
import Nav from '../../../components/Nav';
|
||||||
import ResponsiveForm from '../components/ResponsiveForm';
|
import ResponsiveForm from '../components/ResponsiveForm';
|
||||||
|
|
||||||
const isMobile = () => (window.innerWidth < 770);
|
|
||||||
|
|
||||||
class SignupView extends React.Component {
|
class SignupView extends React.Component {
|
||||||
gotoHomePage = () => {
|
gotoHomePage = () => {
|
||||||
|
@ -26,29 +25,27 @@ class SignupView extends React.Component {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<ResponsiveForm mobile={isMobile() || this.props.mobile}>
|
<div className="signup">
|
||||||
<div className="signup">
|
<Nav layout="dashboard" />
|
||||||
<Nav layout="dashboard" />
|
<main className="form-container">
|
||||||
<main className="form-container">
|
<Helmet>
|
||||||
<Helmet>
|
<title>{this.props.t('SignupView.Title')}</title>
|
||||||
<title>{this.props.t('SignupView.Title')}</title>
|
</Helmet>
|
||||||
</Helmet>
|
<div className="form-container__content">
|
||||||
<div className="form-container__content">
|
<h2 className="form-container__title">{this.props.t('SignupView.Description')}</h2>
|
||||||
<h2 className="form-container__title">{this.props.t('SignupView.Description')}</h2>
|
<SignupForm {...this.props} />
|
||||||
<SignupForm {...this.props} />
|
<h2 className="form-container__divider">{this.props.t('SignupView.Or')}</h2>
|
||||||
<h2 className="form-container__divider">{this.props.t('SignupView.Or')}</h2>
|
<div className="form-container__stack">
|
||||||
<div className="form-container__stack">
|
<SocialAuthButton service={SocialAuthButton.services.github} />
|
||||||
<SocialAuthButton service={SocialAuthButton.services.github} />
|
<SocialAuthButton service={SocialAuthButton.services.google} />
|
||||||
<SocialAuthButton service={SocialAuthButton.services.google} />
|
|
||||||
</div>
|
|
||||||
<p className="form__navigation-options">
|
|
||||||
{this.props.t('SignupView.AlreadyHave')}
|
|
||||||
<Link className="form__login-button" to="/login">{this.props.t('SignupView.Login')}</Link>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</main>
|
<p className="form__navigation-options">
|
||||||
</div>
|
{this.props.t('SignupView.AlreadyHave')}
|
||||||
</ResponsiveForm>
|
<Link className="form__login-button" to="/login">{this.props.t('SignupView.Login')}</Link>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,14 +113,12 @@ SignupView.propTypes = {
|
||||||
authenticated: PropTypes.bool
|
authenticated: PropTypes.bool
|
||||||
}),
|
}),
|
||||||
t: PropTypes.func.isRequired,
|
t: PropTypes.func.isRequired,
|
||||||
mobile: PropTypes.bool
|
|
||||||
};
|
};
|
||||||
|
|
||||||
SignupView.defaultProps = {
|
SignupView.defaultProps = {
|
||||||
user: {
|
user: {
|
||||||
authenticated: false
|
authenticated: false
|
||||||
},
|
},
|
||||||
mobile: false
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default withTranslation()(reduxForm({
|
export default withTranslation()(reduxForm({
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { Route, IndexRoute } from 'react-router';
|
import { Route, IndexRoute } from 'react-router';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import App from './modules/App/App';
|
import App from './modules/App/App';
|
||||||
import IDEView from './modules/IDE/pages/IDEView';
|
import IDEView from './modules/IDE/pages/IDEView';
|
||||||
import MobileIDEView from './modules/IDE/pages/MobileIDEView';
|
import MobileIDEView from './modules/IDE/pages/MobileIDEView';
|
||||||
|
@ -19,6 +20,7 @@ import MobileDashboardView from './modules/Mobile/MobileDashboardView';
|
||||||
import { getUser } from './modules/User/actions';
|
import { getUser } from './modules/User/actions';
|
||||||
import { stopSketch } from './modules/IDE/actions/ide';
|
import { stopSketch } from './modules/IDE/actions/ide';
|
||||||
import { userIsAuthenticated, userIsNotAuthenticated, userIsAuthorized } from './utils/auth';
|
import { userIsAuthenticated, userIsNotAuthenticated, userIsAuthorized } from './utils/auth';
|
||||||
|
import { mobileFirst, responsiveForm } from './utils/responsive';
|
||||||
|
|
||||||
const checkAuth = (store) => {
|
const checkAuth = (store) => {
|
||||||
store.dispatch(getUser());
|
store.dispatch(getUser());
|
||||||
|
@ -27,16 +29,17 @@ const checkAuth = (store) => {
|
||||||
// TODO: This short-circuit seems unnecessary - using the mobile <Switch /> navigator (future) should prevent this from being called
|
// TODO: This short-circuit seems unnecessary - using the mobile <Switch /> navigator (future) should prevent this from being called
|
||||||
const onRouteChange = (store) => {
|
const onRouteChange = (store) => {
|
||||||
const path = window.location.pathname;
|
const path = window.location.pathname;
|
||||||
if (path.includes('/mobile/preview')) return;
|
if (path.includes('preview')) return;
|
||||||
|
|
||||||
store.dispatch(stopSketch());
|
store.dispatch(stopSketch());
|
||||||
};
|
};
|
||||||
|
|
||||||
const routes = store => (
|
const routes = store => (
|
||||||
<Route path="/" component={App} onChange={() => { onRouteChange(store); }}>
|
<Route path="/" component={App} onChange={() => { onRouteChange(store); }}>
|
||||||
<IndexRoute component={IDEView} onEnter={checkAuth(store)} />
|
<IndexRoute onEnter={checkAuth(store)} component={mobileFirst(MobileIDEView, IDEView)} />
|
||||||
<Route path="/login" component={userIsNotAuthenticated(LoginView)} />
|
|
||||||
<Route path="/signup" component={userIsNotAuthenticated(SignupView)} />
|
<Route path="/login" component={userIsNotAuthenticated(mobileFirst(responsiveForm(LoginView), LoginView))} />
|
||||||
|
<Route path="/signup" component={userIsNotAuthenticated(mobileFirst(responsiveForm(SignupView), SignupView))} />
|
||||||
<Route path="/reset-password" component={userIsNotAuthenticated(ResetPasswordView)} />
|
<Route path="/reset-password" component={userIsNotAuthenticated(ResetPasswordView)} />
|
||||||
<Route path="/verify" component={EmailVerificationView} />
|
<Route path="/verify" component={EmailVerificationView} />
|
||||||
<Route
|
<Route
|
||||||
|
@ -46,28 +49,24 @@ const routes = store => (
|
||||||
<Route path="/projects/:project_id" component={IDEView} />
|
<Route path="/projects/:project_id" component={IDEView} />
|
||||||
<Route path="/:username/full/:project_id" component={FullView} />
|
<Route path="/:username/full/:project_id" component={FullView} />
|
||||||
<Route path="/full/:project_id" component={FullView} />
|
<Route path="/full/:project_id" component={FullView} />
|
||||||
<Route path="/sketches" component={createRedirectWithUsername('/:username/sketches')} />
|
|
||||||
<Route path="/:username/assets" component={userIsAuthenticated(userIsAuthorized(DashboardView))} />
|
<Route path="/:username/assets" component={userIsAuthenticated(userIsAuthorized(mobileFirst(MobileDashboardView, DashboardView)))} />
|
||||||
<Route path="/assets" component={createRedirectWithUsername('/:username/assets')} />
|
<Route path="/:username/sketches" component={mobileFirst(MobileDashboardView, DashboardView)} />
|
||||||
<Route path="/account" component={userIsAuthenticated(AccountView)} />
|
<Route path="/:username/sketches/:project_id" component={mobileFirst(MobileIDEView, IDEView)} />
|
||||||
<Route path="/:username/sketches/:project_id" component={IDEView} />
|
<Route path="/:username/sketches/:project_id/add-to-collection" component={mobileFirst(MobileIDEView, IDEView)} />
|
||||||
<Route path="/:username/sketches/:project_id/add-to-collection" component={IDEView} />
|
<Route path="/:username/collections" component={mobileFirst(MobileDashboardView, DashboardView)} />
|
||||||
<Route path="/:username/sketches" component={DashboardView} />
|
|
||||||
<Route path="/:username/collections" component={DashboardView} />
|
|
||||||
<Route path="/:username/collections/create" component={DashboardView} />
|
<Route path="/:username/collections/create" component={DashboardView} />
|
||||||
<Route path="/:username/collections/:collection_id" component={CollectionView} />
|
<Route path="/:username/collections/:collection_id" component={CollectionView} />
|
||||||
|
|
||||||
|
<Route path="/sketches" component={createRedirectWithUsername('/:username/sketches')} />
|
||||||
|
<Route path="/assets" component={createRedirectWithUsername('/:username/assets')} />
|
||||||
|
<Route path="/account" component={userIsAuthenticated(AccountView)} />
|
||||||
<Route path="/about" component={IDEView} />
|
<Route path="/about" component={IDEView} />
|
||||||
|
|
||||||
|
{/* Mobile-only Routes */}
|
||||||
<Route path="/mobile/preview" component={MobileSketchView} />
|
<Route path="/preview" component={MobileSketchView} />
|
||||||
<Route path="/mobile/preferences" component={MobilePreferences} />
|
<Route path="/preferences" component={MobilePreferences} />
|
||||||
<Route path="/mobile" component={MobileIDEView} />
|
|
||||||
|
|
||||||
<Route path="/mobile/:username/sketches/:project_id" component={MobileIDEView} />
|
|
||||||
<Route path="/mobile/:username/assets" component={userIsAuthenticated(userIsAuthorized(MobileDashboardView))} />
|
|
||||||
<Route path="/mobile/:username/sketches" component={MobileDashboardView} />
|
|
||||||
<Route path="/mobile/:username/collections" component={MobileDashboardView} />
|
|
||||||
<Route path="/mobile/:username/collections/create" component={MobileDashboardView} />
|
|
||||||
|
|
||||||
</Route>
|
</Route>
|
||||||
);
|
);
|
||||||
|
|
23
client/utils/responsive.jsx
Normal file
23
client/utils/responsive.jsx
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import MediaQuery from 'react-responsive';
|
||||||
|
import ResponsiveForm from '../modules/User/components/ResponsiveForm';
|
||||||
|
|
||||||
|
export const mobileEnabled = () => (window.process.env.MOBILE_ENABLED === true);
|
||||||
|
|
||||||
|
export const mobileFirst = (MobileComponent, Fallback) => (props) => {
|
||||||
|
const { forceDesktop } = useSelector(state => state.editorAccessibility);
|
||||||
|
return (
|
||||||
|
<MediaQuery minWidth={770}>
|
||||||
|
{matches => ((matches || forceDesktop || (!mobileEnabled()))
|
||||||
|
? <Fallback {...props} />
|
||||||
|
: <MobileComponent {...props} />)}
|
||||||
|
</MediaQuery>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const responsiveForm = DesktopComponent => props => (
|
||||||
|
<ResponsiveForm>
|
||||||
|
<DesktopComponent {...props} />
|
||||||
|
</ResponsiveForm>
|
||||||
|
);
|
32
package-lock.json
generated
32
package-lock.json
generated
|
@ -13124,6 +13124,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"css-mediaquery": {
|
||||||
|
"version": "0.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-mediaquery/-/css-mediaquery-0.1.2.tgz",
|
||||||
|
"integrity": "sha1-aiw3NEkoYYYxxUvTPO3TAdoYvqA="
|
||||||
|
},
|
||||||
"css-select": {
|
"css-select": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
|
||||||
|
@ -19020,6 +19025,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"hyphenate-style-name": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ=="
|
||||||
|
},
|
||||||
"i18next": {
|
"i18next": {
|
||||||
"version": "19.5.4",
|
"version": "19.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-19.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/i18next/-/i18next-19.5.4.tgz",
|
||||||
|
@ -25866,6 +25876,14 @@
|
||||||
"unquote": "^1.1.0"
|
"unquote": "^1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"matchmediaquery": {
|
||||||
|
"version": "0.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/matchmediaquery/-/matchmediaquery-0.3.1.tgz",
|
||||||
|
"integrity": "sha512-Hlk20WQHRIm9EE9luN1kjRjYXAQToHOIAHPJn9buxBwuhfTHoKUcX+lXBbxc85DVQfXYbEQ4HcwQdd128E3qHQ==",
|
||||||
|
"requires": {
|
||||||
|
"css-mediaquery": "^0.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"material-colors": {
|
"material-colors": {
|
||||||
"version": "1.2.6",
|
"version": "1.2.6",
|
||||||
"resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz",
|
"resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz",
|
||||||
|
@ -32233,6 +32251,17 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-responsive": {
|
||||||
|
"version": "8.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-responsive/-/react-responsive-8.1.0.tgz",
|
||||||
|
"integrity": "sha512-U8Nv2/ZWACIw/fAE9XNPbc2Xo33X5q1bcCASc2SufvJ9ifB+o/rokfogfznSVcvS22hN1rafGi0uZD6GiVFEHw==",
|
||||||
|
"requires": {
|
||||||
|
"hyphenate-style-name": "^1.0.0",
|
||||||
|
"matchmediaquery": "^0.3.0",
|
||||||
|
"prop-types": "^15.6.1",
|
||||||
|
"shallow-equal": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-router": {
|
"react-router": {
|
||||||
"version": "3.2.5",
|
"version": "3.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-3.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/react-router/-/react-router-3.2.5.tgz",
|
||||||
|
@ -34519,8 +34548,7 @@
|
||||||
"shallow-equal": {
|
"shallow-equal": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz",
|
||||||
"integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==",
|
"integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"shallowequal": {
|
"shallowequal": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
|
|
|
@ -201,6 +201,7 @@
|
||||||
"react-hot-loader": "^4.12.19",
|
"react-hot-loader": "^4.12.19",
|
||||||
"react-i18next": "^11.5.0",
|
"react-i18next": "^11.5.0",
|
||||||
"react-redux": "^7.2.0",
|
"react-redux": "^7.2.0",
|
||||||
|
"react-responsive": "^8.1.0",
|
||||||
"react-router": "^3.2.5",
|
"react-router": "^3.2.5",
|
||||||
"react-split-pane": "^0.1.89",
|
"react-split-pane": "^0.1.89",
|
||||||
"react-tabs": "^2.3.1",
|
"react-tabs": "^2.3.1",
|
||||||
|
|
|
@ -132,10 +132,6 @@ app.get(
|
||||||
// isomorphic rendering
|
// isomorphic rendering
|
||||||
app.use('/', serverRoutes);
|
app.use('/', serverRoutes);
|
||||||
|
|
||||||
if (process.env.MOBILE_ENABLED) {
|
|
||||||
app.use('/mobile', serverRoutes);
|
|
||||||
}
|
|
||||||
|
|
||||||
app.use(assetRoutes);
|
app.use(assetRoutes);
|
||||||
|
|
||||||
app.use('/', embedRoutes);
|
app.use('/', embedRoutes);
|
||||||
|
|
|
@ -33,7 +33,7 @@ export function renderIndex() {
|
||||||
window.process.env.UI_COLLECTIONS_ENABLED = ${process.env.UI_COLLECTIONS_ENABLED === 'false' ? false : true};
|
window.process.env.UI_COLLECTIONS_ENABLED = ${process.env.UI_COLLECTIONS_ENABLED === 'false' ? false : true};
|
||||||
window.process.env.UPLOAD_LIMIT = ${process.env.UPLOAD_LIMIT ? `${process.env.UPLOAD_LIMIT}` : undefined};
|
window.process.env.UPLOAD_LIMIT = ${process.env.UPLOAD_LIMIT ? `${process.env.UPLOAD_LIMIT}` : undefined};
|
||||||
window.process.env.MOBILE_ENABLED = ${process.env.MOBILE_ENABLED ? `${process.env.MOBILE_ENABLED}` : undefined};
|
window.process.env.MOBILE_ENABLED = ${process.env.MOBILE_ENABLED ? `${process.env.MOBILE_ENABLED}` : undefined};
|
||||||
window.process.env.TRANSLATIONS_ENABLED = ${process.env.TRANSLATIONS_ENABLED === 'true' ? true :false};
|
window.process.env.TRANSLATIONS_ENABLED = ${process.env.TRANSLATIONS_ENABLED === 'true' ? true : false};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
Loading…
Reference in a new issue