mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Improve homepage layout and Create project dialog options (#3386)
This commit is contained in:
@@ -8,7 +8,6 @@ import Authentication from './Utils/GDevelopServices/Authentication';
|
||||
import './UI/icomoon-font.css'; // Styles for Icomoon font.
|
||||
|
||||
// Import for browser only IDE
|
||||
import BrowserExamples from './ProjectCreation/BrowserExamples';
|
||||
import BrowserIntroDialog from './MainFrame/BrowserIntroDialog';
|
||||
import browserResourceSources from './ResourcesList/BrowserResourceSources';
|
||||
import browserResourceExternalEditors from './ResourcesList/BrowserResourceExternalEditors';
|
||||
@@ -84,7 +83,7 @@ export const create = (authentication: Authentication) => {
|
||||
renderCreateDialog={props => (
|
||||
<CreateProjectDialog
|
||||
{...props}
|
||||
examplesComponent={BrowserExamples}
|
||||
onCreateBlank={onCreateBlank}
|
||||
onCreateFromExampleShortHeader={onCreateFromExampleShortHeader}
|
||||
/>
|
||||
)}
|
||||
|
@@ -8,7 +8,6 @@ import Authentication from './Utils/GDevelopServices/Authentication';
|
||||
import './UI/icomoon-font.css'; // Styles for Icomoon font.
|
||||
|
||||
// Import for Electron powered IDE.
|
||||
import LocalExamples from './ProjectCreation/LocalExamples';
|
||||
import localResourceSources from './ResourcesList/LocalResourceSources';
|
||||
import localResourceExternalEditors from './ResourcesList/LocalResourceExternalEditors';
|
||||
import LocalPreviewLauncher from './Export/LocalExporters/LocalPreviewLauncher';
|
||||
@@ -82,7 +81,7 @@ export const create = (authentication: Authentication) => {
|
||||
renderCreateDialog={props => (
|
||||
<CreateProjectDialog
|
||||
{...props}
|
||||
examplesComponent={LocalExamples}
|
||||
onCreateBlank={onCreateBlank}
|
||||
onCreateFromExampleShortHeader={
|
||||
onCreateFromExampleShortHeader
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@ import { Trans, t } from '@lingui/macro';
|
||||
import Language from '@material-ui/icons/Language';
|
||||
import ForumIcon from '@material-ui/icons/Forum';
|
||||
import HelpIcon from '@material-ui/icons/Help';
|
||||
import AddCircleOutline from '@material-ui/icons/AddCircleOutline';
|
||||
|
||||
import FlatButton from '../../../UI/FlatButton';
|
||||
import IconButton from '../../../UI/IconButton';
|
||||
@@ -330,7 +331,7 @@ export const HomePage = React.memo<Props>(
|
||||
onClick={() => {
|
||||
openPreCreationDialog(true);
|
||||
}}
|
||||
primary
|
||||
icon={<AddCircleOutline />}
|
||||
/>
|
||||
)}
|
||||
{!project && canOpen && (
|
||||
@@ -363,7 +364,7 @@ export const HomePage = React.memo<Props>(
|
||||
</ResponsiveLineStackLayout>
|
||||
</div>
|
||||
<Carousel
|
||||
title={<Trans>Start from a template</Trans>}
|
||||
title={<Trans>Start from an example</Trans>}
|
||||
items={examples ? prepareExamples(examples) : null}
|
||||
displayItemTitles
|
||||
onBrowseAllClick={onOpenExamples}
|
||||
@@ -534,6 +535,9 @@ export const HomePage = React.memo<Props>(
|
||||
isOpening={isOpening}
|
||||
onClose={() => openPreCreationDialog(false)}
|
||||
onCreate={() => createProject(i18n)}
|
||||
onClickGenerateProjectName={() =>
|
||||
setNewProjectName(generateName())
|
||||
}
|
||||
outputPath={electron ? outputPath : undefined}
|
||||
onChangeOutputPath={electron ? setOutputPath : undefined}
|
||||
projectName={newProjectName}
|
||||
|
@@ -1,74 +0,0 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import { I18n } from '@lingui/react';
|
||||
import { type I18n as I18nType } from '@lingui/core';
|
||||
import { ExampleStore } from '../AssetStore/ExampleStore';
|
||||
import { type ExampleShortHeader } from '../Utils/GDevelopServices/Example';
|
||||
import {
|
||||
type OnCreateFromExampleShortHeaderFunction,
|
||||
type OnOpenProjectAfterCreationFunction,
|
||||
} from '../ProjectCreation/CreateProjectDialog';
|
||||
import ProjectPreCreationDialog from './ProjectPreCreationDialog';
|
||||
import generateName from '../Utils/ProjectNameGenerator';
|
||||
|
||||
type Props = {|
|
||||
onOpen: OnOpenProjectAfterCreationFunction,
|
||||
onCreateFromExampleShortHeader: OnCreateFromExampleShortHeaderFunction,
|
||||
|};
|
||||
|
||||
export default function BrowserExamples({
|
||||
onOpen,
|
||||
onCreateFromExampleShortHeader,
|
||||
}: Props) {
|
||||
const [
|
||||
selectedExampleShortHeader,
|
||||
setSelectedExampleShortShortHeader,
|
||||
] = React.useState<?ExampleShortHeader>(null);
|
||||
const [newProjectName, setNewProjectName] = React.useState<string>(
|
||||
generateName()
|
||||
);
|
||||
const [isOpening, setIsOpening] = React.useState(false);
|
||||
|
||||
const createProjectFromExample = async (i18n: I18nType) => {
|
||||
if (!selectedExampleShortHeader) return;
|
||||
|
||||
setIsOpening(true);
|
||||
try {
|
||||
const projectMetadata = await onCreateFromExampleShortHeader({
|
||||
i18n,
|
||||
projectName: newProjectName,
|
||||
exampleShortHeader: selectedExampleShortHeader,
|
||||
});
|
||||
if (projectMetadata) {
|
||||
onOpen({ ...projectMetadata, shouldCloseDialog: true });
|
||||
}
|
||||
} finally {
|
||||
setIsOpening(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<I18n>
|
||||
{({ i18n }) => (
|
||||
<>
|
||||
<ExampleStore
|
||||
isOpening={isOpening}
|
||||
onOpen={async (example: ?ExampleShortHeader) =>
|
||||
setSelectedExampleShortShortHeader(example)
|
||||
}
|
||||
/>
|
||||
{selectedExampleShortHeader && (
|
||||
<ProjectPreCreationDialog
|
||||
open
|
||||
isOpening={isOpening}
|
||||
onClose={() => setSelectedExampleShortShortHeader(null)}
|
||||
onCreate={() => createProjectFromExample(i18n)}
|
||||
projectName={newProjectName}
|
||||
onChangeProjectName={setNewProjectName}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</I18n>
|
||||
);
|
||||
}
|
@@ -1,8 +1,11 @@
|
||||
// @flow
|
||||
import { Trans } from '@lingui/macro';
|
||||
import { I18n } from '@lingui/react';
|
||||
import { type I18n as I18nType } from '@lingui/core';
|
||||
|
||||
import * as React from 'react';
|
||||
import PublishIcon from '@material-ui/icons/Publish';
|
||||
|
||||
import { ExampleStore } from '../AssetStore/ExampleStore';
|
||||
import Dialog from '../UI/Dialog';
|
||||
import FlatButton from '../UI/FlatButton';
|
||||
import { Tabs, Tab } from '../UI/Tabs';
|
||||
@@ -12,9 +15,11 @@ import { type StorageProvider, type FileMetadata } from '../ProjectsStorage';
|
||||
import { GamesShowcase } from '../GamesShowcase';
|
||||
import { type ExampleShortHeader } from '../Utils/GDevelopServices/Example';
|
||||
import Window from '../Utils/Window';
|
||||
import PublishIcon from '@material-ui/icons/Publish';
|
||||
import ProjectPreCreationDialog from './ProjectPreCreationDialog';
|
||||
import { findEmptyPathInDefaultFolder } from './LocalPathFinder';
|
||||
import optionalRequire from '../Utils/OptionalRequire.js';
|
||||
import RaisedButton from '../UI/RaisedButton';
|
||||
import generateName from '../Utils/ProjectNameGenerator';
|
||||
const electron = optionalRequire('electron');
|
||||
const app = electron ? electron.remote.app : null;
|
||||
|
||||
@@ -23,11 +28,6 @@ export type CreateProjectDialogTabs =
|
||||
| 'tutorials'
|
||||
| 'games-showcase';
|
||||
|
||||
type State = {|
|
||||
currentTab: CreateProjectDialogTabs,
|
||||
outputPath: string,
|
||||
|};
|
||||
|
||||
export type OnOpenProjectAfterCreationFunction = ({|
|
||||
project?: gdProject,
|
||||
storageProvider: ?StorageProvider,
|
||||
@@ -67,99 +67,191 @@ export type OnCreateFromExampleShortHeaderFunction = ({|
|
||||
|
||||
type Props = {|
|
||||
...CreateProjectDialogWithComponentsProps,
|
||||
examplesComponent: any,
|
||||
onCreateBlank: OnCreateBlankFunction,
|
||||
onCreateFromExampleShortHeader: OnCreateFromExampleShortHeaderFunction,
|
||||
|};
|
||||
|
||||
export default class CreateProjectDialog extends React.Component<Props, State> {
|
||||
state = {
|
||||
currentTab: this.props.initialTab,
|
||||
outputPath: app ? findEmptyPathInDefaultFolder(app) : '',
|
||||
};
|
||||
const CreateProjectDialog = ({
|
||||
open,
|
||||
onClose,
|
||||
onOpen,
|
||||
onCreateFromExampleShortHeader,
|
||||
onCreateBlank,
|
||||
initialTab,
|
||||
}: Props) => {
|
||||
const [currentTab, setCurrentTab] = React.useState<CreateProjectDialogTabs>(
|
||||
initialTab
|
||||
);
|
||||
const [outputPath, setOutputPath] = React.useState<string>(
|
||||
app ? findEmptyPathInDefaultFolder(app) : ''
|
||||
);
|
||||
const [isOpening, setIsOpening] = React.useState<boolean>(false);
|
||||
const [newProjectName, setNewProjectName] = React.useState<string>('');
|
||||
const [
|
||||
selectedExampleShortHeader,
|
||||
setSelectedExampleShortShortHeader,
|
||||
] = React.useState<?ExampleShortHeader>(null);
|
||||
const [
|
||||
preCreationDialogOpen,
|
||||
setPreCreationDialogOpen,
|
||||
] = React.useState<boolean>(false);
|
||||
|
||||
_onChangeTab = (newTab: CreateProjectDialogTabs) => {
|
||||
this.setState({
|
||||
currentTab: newTab,
|
||||
});
|
||||
};
|
||||
const openPreCreationDialog = React.useCallback((open: boolean) => {
|
||||
if (open) {
|
||||
setOutputPath(app ? findEmptyPathInDefaultFolder(app) : '');
|
||||
setNewProjectName(generateName());
|
||||
}
|
||||
setPreCreationDialogOpen(open);
|
||||
}, []);
|
||||
|
||||
_showExamples = () => this._onChangeTab('examples');
|
||||
const actions = React.useMemo(
|
||||
() => [
|
||||
<RaisedButton
|
||||
key="create-blank"
|
||||
label={<Trans>Create a blank project</Trans>}
|
||||
primary={false}
|
||||
onClick={() => openPreCreationDialog(true)}
|
||||
/>,
|
||||
<FlatButton
|
||||
key="close"
|
||||
label={<Trans>Close</Trans>}
|
||||
primary={false}
|
||||
onClick={onClose}
|
||||
/>,
|
||||
],
|
||||
[onClose, openPreCreationDialog]
|
||||
);
|
||||
|
||||
render() {
|
||||
const {
|
||||
open,
|
||||
onClose,
|
||||
onOpen,
|
||||
onCreateFromExampleShortHeader,
|
||||
} = this.props;
|
||||
if (!open) return null;
|
||||
|
||||
const ExamplesComponent = this.props.examplesComponent;
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
title={<Trans>Create a new project</Trans>}
|
||||
actions={[
|
||||
const secondaryActions = React.useMemo(
|
||||
() => {
|
||||
if (currentTab === 'games-showcase')
|
||||
return [
|
||||
<FlatButton
|
||||
key="close"
|
||||
label={<Trans>Close</Trans>}
|
||||
primary={false}
|
||||
onClick={onClose}
|
||||
key="submit-game-showcase"
|
||||
onClick={() => {
|
||||
Window.openExternalURL(
|
||||
'https://docs.google.com/forms/d/e/1FAIpQLSfjiOnkbODuPifSGuzxYY61vB5kyMWdTZSSqkJsv3H6ePRTQA/viewform?usp=sf_link'
|
||||
);
|
||||
}}
|
||||
primary
|
||||
icon={<PublishIcon />}
|
||||
label={<Trans>Submit your game to the showcase</Trans>}
|
||||
/>,
|
||||
]}
|
||||
secondaryActions={[
|
||||
this.state.currentTab === 'games-showcase' ? (
|
||||
<FlatButton
|
||||
key="submit-game-showcase"
|
||||
onClick={() => {
|
||||
Window.openExternalURL(
|
||||
'https://docs.google.com/forms/d/e/1FAIpQLSfjiOnkbODuPifSGuzxYY61vB5kyMWdTZSSqkJsv3H6ePRTQA/viewform?usp=sf_link'
|
||||
);
|
||||
}}
|
||||
primary
|
||||
icon={<PublishIcon />}
|
||||
label={<Trans>Submit your game to the showcase</Trans>}
|
||||
/>
|
||||
) : null,
|
||||
this.state.currentTab === 'examples' ? (
|
||||
<FlatButton
|
||||
key="submit-example"
|
||||
onClick={() => {
|
||||
Window.openExternalURL(
|
||||
'https://github.com/GDevelopApp/GDevelop-examples/issues/new/choose'
|
||||
);
|
||||
}}
|
||||
primary
|
||||
icon={<PublishIcon />}
|
||||
label={<Trans>Submit your project as an example</Trans>}
|
||||
/>
|
||||
) : null,
|
||||
]}
|
||||
cannotBeDismissed={false}
|
||||
onRequestClose={onClose}
|
||||
open={open}
|
||||
noMargin
|
||||
fullHeight
|
||||
flexBody
|
||||
>
|
||||
<Column expand noMargin>
|
||||
<Tabs value={this.state.currentTab} onChange={this._onChangeTab}>
|
||||
<Tab label={<Trans>Examples</Trans>} value="examples" />
|
||||
<Tab label={<Trans>Tutorials</Trans>} value="tutorials" />
|
||||
<Tab label={<Trans>Games showcase</Trans>} value="games-showcase" />
|
||||
</Tabs>
|
||||
{this.state.currentTab === 'examples' && (
|
||||
<ExamplesComponent
|
||||
onOpen={onOpen}
|
||||
onChangeOutputPath={outputPath => this.setState({ outputPath })}
|
||||
outputPath={this.state.outputPath}
|
||||
onCreateFromExampleShortHeader={onCreateFromExampleShortHeader}
|
||||
];
|
||||
if (currentTab === 'examples')
|
||||
return [
|
||||
<FlatButton
|
||||
key="submit-example"
|
||||
onClick={() => {
|
||||
Window.openExternalURL(
|
||||
'https://github.com/GDevelopApp/GDevelop-examples/issues/new/choose'
|
||||
);
|
||||
}}
|
||||
primary
|
||||
icon={<PublishIcon />}
|
||||
label={<Trans>Submit your project as an example</Trans>}
|
||||
/>,
|
||||
];
|
||||
},
|
||||
[currentTab]
|
||||
);
|
||||
|
||||
if (!open) return null;
|
||||
|
||||
const createProject = async (i18n: I18nType) => {
|
||||
setIsOpening(true);
|
||||
|
||||
try {
|
||||
let projectMetadata;
|
||||
|
||||
if (selectedExampleShortHeader) {
|
||||
projectMetadata = await onCreateFromExampleShortHeader({
|
||||
i18n,
|
||||
outputPath,
|
||||
projectName: newProjectName,
|
||||
exampleShortHeader: selectedExampleShortHeader,
|
||||
});
|
||||
} else {
|
||||
projectMetadata = await onCreateBlank({
|
||||
i18n,
|
||||
outputPath,
|
||||
projectName: newProjectName,
|
||||
});
|
||||
}
|
||||
|
||||
if (!projectMetadata) return;
|
||||
|
||||
openPreCreationDialog(false);
|
||||
setSelectedExampleShortShortHeader(null);
|
||||
onOpen({ ...projectMetadata });
|
||||
} finally {
|
||||
setIsOpening(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<I18n>
|
||||
{({ i18n }) => (
|
||||
<>
|
||||
<Dialog
|
||||
title={<Trans>Create a new project</Trans>}
|
||||
actions={actions}
|
||||
secondaryActions={secondaryActions}
|
||||
cannotBeDismissed={false}
|
||||
onRequestClose={onClose}
|
||||
open={open}
|
||||
noMargin
|
||||
fullHeight
|
||||
flexBody
|
||||
>
|
||||
<Column expand noMargin>
|
||||
<Tabs
|
||||
value={currentTab}
|
||||
onChange={(newTab: CreateProjectDialogTabs) => {
|
||||
setCurrentTab(newTab);
|
||||
}}
|
||||
>
|
||||
<Tab label={<Trans>Examples</Trans>} value="examples" />
|
||||
<Tab label={<Trans>Tutorials</Trans>} value="tutorials" />
|
||||
<Tab
|
||||
label={<Trans>Games showcase</Trans>}
|
||||
value="games-showcase"
|
||||
/>
|
||||
</Tabs>
|
||||
{currentTab === 'examples' && (
|
||||
<Column noMargin expand useFullHeight>
|
||||
<ExampleStore
|
||||
isOpening={isOpening}
|
||||
onOpen={async (example: ?ExampleShortHeader) => {
|
||||
setSelectedExampleShortShortHeader(example);
|
||||
openPreCreationDialog(true);
|
||||
}}
|
||||
/>
|
||||
</Column>
|
||||
)}
|
||||
{currentTab === 'tutorials' && <TutorialsList />}
|
||||
{currentTab === 'games-showcase' && <GamesShowcase />}
|
||||
</Column>
|
||||
</Dialog>
|
||||
{preCreationDialogOpen && (
|
||||
<ProjectPreCreationDialog
|
||||
open
|
||||
isOpening={isOpening}
|
||||
onClose={() => openPreCreationDialog(false)}
|
||||
onCreate={() => createProject(i18n)}
|
||||
onClickGenerateProjectName={() =>
|
||||
setNewProjectName(generateName())
|
||||
}
|
||||
outputPath={electron ? outputPath : undefined}
|
||||
onChangeOutputPath={electron ? setOutputPath : undefined}
|
||||
projectName={newProjectName}
|
||||
onChangeProjectName={setNewProjectName}
|
||||
/>
|
||||
)}
|
||||
{this.state.currentTab === 'tutorials' && <TutorialsList />}
|
||||
{this.state.currentTab === 'games-showcase' && <GamesShowcase />}
|
||||
</Column>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
}
|
||||
</>
|
||||
)}
|
||||
</I18n>
|
||||
);
|
||||
};
|
||||
|
||||
export default CreateProjectDialog;
|
||||
|
@@ -1,102 +0,0 @@
|
||||
// @flow
|
||||
import { t } from '@lingui/macro';
|
||||
import { I18n } from '@lingui/react';
|
||||
import { type I18n as I18nType } from '@lingui/core';
|
||||
import * as React from 'react';
|
||||
import Divider from '@material-ui/core/Divider';
|
||||
import { ExampleStore } from '../AssetStore/ExampleStore';
|
||||
import { type ExampleShortHeader } from '../Utils/GDevelopServices/Example';
|
||||
import { Column } from '../UI/Grid';
|
||||
import { showErrorBox } from '../UI/Messages/MessageBox';
|
||||
import ProjectPreCreationDialog from './ProjectPreCreationDialog';
|
||||
import {
|
||||
type OnCreateFromExampleShortHeaderFunction,
|
||||
type OnOpenProjectAfterCreationFunction,
|
||||
} from '../ProjectCreation/CreateProjectDialog';
|
||||
import generateName from '../Utils/ProjectNameGenerator';
|
||||
|
||||
type Props = {|
|
||||
onOpen: OnOpenProjectAfterCreationFunction,
|
||||
onChangeOutputPath: (outputPath: string) => void,
|
||||
outputPath: string,
|
||||
onCreateFromExampleShortHeader: OnCreateFromExampleShortHeaderFunction,
|
||||
|};
|
||||
|
||||
export const showGameFileCreationError = (
|
||||
i18n: I18nType,
|
||||
outputPath: string,
|
||||
rawError: Error
|
||||
) => {
|
||||
showErrorBox({
|
||||
message: i18n._(
|
||||
t`Unable to create the game in the specified folder. Check that you have permissions to write in this folder: ${outputPath} or choose another folder.`
|
||||
),
|
||||
rawError,
|
||||
errorId: 'local-example-creation-error',
|
||||
});
|
||||
};
|
||||
|
||||
export default function LocalExamples({
|
||||
outputPath,
|
||||
onChangeOutputPath,
|
||||
onOpen,
|
||||
onCreateFromExampleShortHeader,
|
||||
}: Props) {
|
||||
const [isOpening, setIsOpening] = React.useState<boolean>(false);
|
||||
const [newProjectName, setNewProjectName] = React.useState<string>(
|
||||
generateName()
|
||||
);
|
||||
const [
|
||||
selectedExampleShortHeader,
|
||||
setSelectedExampleShortShortHeader,
|
||||
] = React.useState<?ExampleShortHeader>(null);
|
||||
|
||||
const createProjectFromExample = async (i18n: I18nType) => {
|
||||
if (!selectedExampleShortHeader) return;
|
||||
|
||||
setIsOpening(true);
|
||||
try {
|
||||
const projectMetadata = await onCreateFromExampleShortHeader({
|
||||
i18n,
|
||||
outputPath,
|
||||
projectName: newProjectName,
|
||||
exampleShortHeader: selectedExampleShortHeader,
|
||||
});
|
||||
if (!!projectMetadata) {
|
||||
onOpen({ ...projectMetadata, shouldCloseDialog: true });
|
||||
}
|
||||
} finally {
|
||||
setIsOpening(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<I18n>
|
||||
{({ i18n }) => (
|
||||
<>
|
||||
<Column noMargin expand useFullHeight>
|
||||
<Divider />
|
||||
<ExampleStore
|
||||
isOpening={isOpening}
|
||||
onOpen={async (example: ?ExampleShortHeader) =>
|
||||
setSelectedExampleShortShortHeader(example)
|
||||
}
|
||||
/>
|
||||
</Column>
|
||||
{selectedExampleShortHeader && (
|
||||
<ProjectPreCreationDialog
|
||||
open
|
||||
isOpening={isOpening}
|
||||
onClose={() => setSelectedExampleShortShortHeader(null)}
|
||||
onCreate={() => createProjectFromExample(i18n)}
|
||||
outputPath={outputPath}
|
||||
onChangeOutputPath={onChangeOutputPath}
|
||||
projectName={newProjectName}
|
||||
onChangeProjectName={setNewProjectName}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</I18n>
|
||||
);
|
||||
}
|
@@ -2,6 +2,7 @@
|
||||
import { Trans } from '@lingui/macro';
|
||||
import * as React from 'react';
|
||||
import Dialog from '../UI/Dialog';
|
||||
import Refresh from '@material-ui/icons/Refresh';
|
||||
import FlatButton from '../UI/FlatButton';
|
||||
import RaisedButton from '../UI/RaisedButton';
|
||||
import { Column, Spacer } from '../UI/Grid';
|
||||
@@ -13,6 +14,7 @@ type Props = {|
|
||||
isOpening?: boolean,
|
||||
onClose: () => void,
|
||||
onCreate: () => void | Promise<void>,
|
||||
onClickGenerateProjectName: () => void,
|
||||
outputPath?: string,
|
||||
onChangeOutputPath?: (outputPath: string) => void,
|
||||
projectName: string,
|
||||
@@ -24,6 +26,7 @@ const ProjectPreCreationDialog = ({
|
||||
isOpening,
|
||||
onClose,
|
||||
onCreate,
|
||||
onClickGenerateProjectName,
|
||||
outputPath,
|
||||
onChangeOutputPath,
|
||||
projectName,
|
||||
@@ -57,7 +60,7 @@ const ProjectPreCreationDialog = ({
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
title={<Trans>Project settings</Trans>}
|
||||
title={<Trans>New Project</Trans>}
|
||||
maxWidth="sm"
|
||||
open={open}
|
||||
onRequestClose={onClose}
|
||||
@@ -77,7 +80,7 @@ const ProjectPreCreationDialog = ({
|
||||
/>,
|
||||
]}
|
||||
>
|
||||
<Column>
|
||||
<Column noMargin>
|
||||
<TextField
|
||||
type="text"
|
||||
errorText={projectNameError}
|
||||
@@ -85,6 +88,7 @@ const ProjectPreCreationDialog = ({
|
||||
value={projectName}
|
||||
onChange={_onChangeProjectName}
|
||||
floatingLabelText={<Trans>Project name</Trans>}
|
||||
endAdornment={<Refresh onClick={onClickGenerateProjectName} />}
|
||||
/>
|
||||
{onChangeOutputPath && (
|
||||
<>
|
||||
|
@@ -1,6 +1,7 @@
|
||||
// @flow
|
||||
import axios from 'axios';
|
||||
import { t } from '@lingui/macro';
|
||||
import { type I18n as I18nType } from '@lingui/core';
|
||||
|
||||
import LocalFileStorageProvider from '../../ProjectsStorage/LocalFileStorageProvider';
|
||||
import optionalRequire from '../../Utils/OptionalRequire.js';
|
||||
@@ -8,7 +9,6 @@ import { getExample } from '../../Utils/GDevelopServices/Example';
|
||||
import { sendNewGameCreated } from '../../Utils/Analytics/EventSender';
|
||||
import { showErrorBox } from '../../UI/Messages/MessageBox';
|
||||
import { writeAndCheckFile } from '../../ProjectsStorage/LocalFileStorageProvider/LocalProjectWriter';
|
||||
import { showGameFileCreationError } from '../LocalExamples';
|
||||
import {
|
||||
type OnCreateBlankFunction,
|
||||
type OnCreateFromExampleShortHeaderFunction,
|
||||
@@ -28,7 +28,13 @@ export const onCreateBlank: OnCreateBlankFunction = async ({
|
||||
try {
|
||||
fs.mkdirsSync(outputPath);
|
||||
} catch (error) {
|
||||
showGameFileCreationError(i18n, outputPath, error);
|
||||
showErrorBox({
|
||||
message: i18n._(
|
||||
t`Unable to create the game in the specified folder. Check that you have permissions to write in this folder: ${outputPath} or choose another folder.`
|
||||
),
|
||||
rawError: error,
|
||||
errorId: 'local-example-creation-error',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -6,6 +6,7 @@ import GridList from '@material-ui/core/GridList';
|
||||
import { GridListTile } from '@material-ui/core';
|
||||
import ArrowBackIos from '@material-ui/icons/ArrowBackIos';
|
||||
import ArrowForwardIos from '@material-ui/icons/ArrowForwardIos';
|
||||
import ListOutlined from '@material-ui/icons/ListOutlined';
|
||||
import { Skeleton } from '@material-ui/lab';
|
||||
|
||||
import Window from '../Utils/Window';
|
||||
@@ -375,6 +376,7 @@ const Carousel = <ThumbnailType: Thumbnail>({
|
||||
(browseAllLink ? openLinkCallback(browseAllLink) : () => {})
|
||||
}
|
||||
label={<Trans>Browse all</Trans>}
|
||||
icon={<ListOutlined />}
|
||||
/>
|
||||
</Line>
|
||||
{error ? (
|
||||
|
@@ -22,6 +22,9 @@ export const Open = () => {
|
||||
onChangeOutputPath={action('change output path')}
|
||||
onClose={() => action('click on close')()}
|
||||
onCreate={() => action('click on create')()}
|
||||
onClickGenerateProjectName={() =>
|
||||
action('click on generate new project name')()
|
||||
}
|
||||
projectName={projectName}
|
||||
onChangeProjectName={setProjectName}
|
||||
/>
|
||||
@@ -38,6 +41,9 @@ export const Disabled = () => {
|
||||
onChangeOutputPath={action('change output path')}
|
||||
onClose={() => action('click on close')()}
|
||||
onCreate={() => action('click on create')()}
|
||||
onClickGenerateProjectName={() =>
|
||||
action('click on generate new project name')()
|
||||
}
|
||||
projectName={projectName}
|
||||
onChangeProjectName={setProjectName}
|
||||
/>
|
||||
|
@@ -2852,10 +2852,10 @@ storiesOf('Project Creation/CreateProjectDialog', module)
|
||||
<ExampleStoreStateProvider>
|
||||
<CreateProjectDialog
|
||||
open
|
||||
examplesComponent={Placeholder}
|
||||
onClose={action('onClose')}
|
||||
onOpen={action('onOpen')}
|
||||
onOpen={action('On open project after it is created')}
|
||||
initialTab="examples"
|
||||
onCreateBlank={() => action('create blank project')}
|
||||
onCreateFromExampleShortHeader={() => action('create from example')}
|
||||
/>
|
||||
</ExampleStoreStateProvider>
|
||||
@@ -2864,10 +2864,10 @@ storiesOf('Project Creation/CreateProjectDialog', module)
|
||||
<ExampleStoreStateProvider>
|
||||
<CreateProjectDialog
|
||||
open
|
||||
examplesComponent={Placeholder}
|
||||
onClose={action('onClose')}
|
||||
onOpen={action('onOpen')}
|
||||
onOpen={action('On open project after it is created')}
|
||||
initialTab="games-showcase"
|
||||
onCreateBlank={() => action('create blank project')}
|
||||
onCreateFromExampleShortHeader={() => action('create from example')}
|
||||
/>
|
||||
</ExampleStoreStateProvider>
|
||||
|
Reference in New Issue
Block a user