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

feat(web): Re:Earth Beta routing and basic component structure #444

Merged
merged 12 commits into from
May 26, 2023
81 changes: 49 additions & 32 deletions web/src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { Suspense } from "react";
import { BrowserRouter as Router, useRoutes, Navigate, useParams } from "react-router-dom";
import { BrowserRouter as Router, Navigate, useParams, Routes, Route } from "react-router-dom";

// import BetaEditor from "@reearth/beta/pages/Editor";
isoppp marked this conversation as resolved.
Show resolved Hide resolved
import Loading from "@reearth/classic/components/atoms/Loading";
import NotificationBanner from "@reearth/classic/components/organisms/Notification";
import LoginPage from "@reearth/classic/components/pages/Authentication/LoginPage";
Expand All @@ -24,39 +25,15 @@ import { Provider as Auth0Provider } from "./services/auth";
import { Provider as GqlProvider } from "./services/gql";
import { Provider as ThemeProvider, styled } from "./services/theme";

const BetaEditor = React.lazy(() => import("@reearth/beta/pages/Editor"));

const EarthEditor = React.lazy(() => import("@reearth/classic/components/pages/EarthEditor"));
const Dashboard = React.lazy(() => import("@reearth/classic/components/pages/Dashboard"));
const GraphQLPlayground = React.lazy(
() => import("@reearth/classic/components/pages/GraphQLPlayground"),
);
const PluginEditor = React.lazy(() => import("./classic/components/pages/PluginEditor"));

function AppRoutes() {
return useRoutes([
{ path: "/", element: <RootPage /> },
{ path: "/login", element: <LoginPage /> },
{ path: "/signup", element: <SignupPage /> },
{ path: "/password-reset", element: <PasswordResetPage /> },
{ path: "/dashboard/:workspaceId", element: <Dashboard /> },
{ path: "/edit/:sceneId", element: <EarthEditor /> },
{ path: "/edit/:sceneId/preview", element: <Preview /> },
{ path: "/settings", element: <Navigate to="/settings/account" /> },
{ path: "/settings/account", element: <AccountSettings /> },
{ path: "/settings/workspaces", element: <WorkspaceList /> },
{ path: "/settings/workspaces/:workspaceId", element: <WorkspaceSettings /> },
{ path: "/settings/workspaces/:workspaceId/projects", element: <SettingsProjectList /> },
{ path: "/settings/workspaces/:workspaceId/asset", element: <AssetSettings /> },
{ path: "/settings/projects/:projectId", element: <ProjectSettings /> },
{ path: "/settings/projects/:projectId/public", element: <PublicSettings /> },
{ path: "/settings/projects/:projectId/dataset", element: <DatasetSettings /> },
{ path: "/settings/projects/:projectId/plugins", element: <PluginSettings /> },
{ path: "/plugin-editor", element: <PluginEditor /> },
{ path: "/graphql", element: import.meta.env.DEV && <GraphQLPlayground /> },
...redirects,
{ path: "*", element: <NotFound /> },
]);
}

export default function App() {
return (
<Auth0Provider>
Expand All @@ -66,7 +43,50 @@ export default function App() {
<Suspense fallback={<Loading />}>
<NotificationBanner />
<StyledRouter>
<AppRoutes />
<Routes>
isoppp marked this conversation as resolved.
Show resolved Hide resolved
<Route path="/" element={<RootPage />} />
<Route path="/login" element={<LoginPage />} />
<Route path="/signup" element={<SignupPage />} />
<Route path="/password-reset" element={<PasswordResetPage />} />
<Route path="/dashboard/:workspaceId" element={<Dashboard />} />
{/* classic routes - start */}
<Route path="/edit/:sceneId" element={<EarthEditor />} />
<Route path="/edit/:sceneId/preview" element={<Preview />} />
<Route path="/plugin-editor" element={<PluginEditor />} />
{/* classic routes - end */}
<Route path="/scene/:sceneId" element={<BetaEditor />}>
<Route path="story" element={<BetaEditor />} />
<Route path="widgets" element={<BetaEditor />} />
<Route path="publish" element={<BetaEditor />} />
</Route>
<Route path="settings" element={<Navigate to="/settings/account" />} />
<Route path="/settings/account" element={<AccountSettings />} />
<Route path="/settings/workspaces" element={<WorkspaceList />} />
<Route path="/settings/workspaces/:workspaceId" element={<WorkspaceSettings />} />
<Route
path="/settings/workspaces/:workspaceId/projects"
element={<SettingsProjectList />}
/>
<Route
path="/settings/workspaces/:workspaceId/asset"
element={<AssetSettings />}
/>
<Route path="/settings/projects/:projectId" element={<ProjectSettings />} />
<Route path="/settings/projects/:projectId/public" element={<PublicSettings />} />
<Route
path="/settings/projects/:projectId/dataset"
element={<DatasetSettings />}
/>
<Route
path="/settings/projects/:projectId/plugins"
element={<PluginSettings />}
/>
isoppp marked this conversation as resolved.
Show resolved Hide resolved
<Route path="/graphql" element={<GraphQLPlayground />} />
{...redirects.map(([from, to]) => (
<Route key={from} path={from} element={<Redirect to={to} />} />
))}
<Route path="*" element={<NotFound />} />
</Routes>
</StyledRouter>
</Suspense>
</I18nProvider>
Expand All @@ -89,10 +109,7 @@ const redirects = [
["/settings/project/:projectId/public", "/settings/projects/:projectId/public"],
["/settings/project/:projectId/dataset", "/settings/projects/:projectId/dataset"],
["/settings/project/:projectId/plugins", "/settings/projects/:projectId/plugins"],
].map(([from, to]) => ({
path: from,
element: <Redirect to={to} />,
}));
];

function Redirect({ to }: { to: string }) {
const { teamId, projectId } = useParams();
Expand Down
12 changes: 12 additions & 0 deletions web/src/beta/features/LeftPanel/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { styled } from "@reearth/services/theme";

const LeftPanel: React.FC = () => {
return <Wrapper>LeftPanel</Wrapper>;
};

export default LeftPanel;

const Wrapper = styled.div`
background: #232226;
width: 235px;
`;
54 changes: 54 additions & 0 deletions web/src/beta/features/Navbar/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { useNavbarHooks, Tab } from "@reearth/beta/hooks/navbarHooks";
import { styled } from "@reearth/services/theme";

export type { Tab };

type Props = {
sceneId?: string;
currentTab?: Tab;
};

const Navbar: React.FC<Props> = ({ sceneId, currentTab }) => {
const { handleEditorNavigation } = useNavbarHooks({ sceneId });

return (
<Wrapper>
<p>Navbar</p>
<div>
<p>current path: {location.pathname}</p>
<p> current tab: {currentTab}</p>
</div>
<div>
<button
onClick={() => handleEditorNavigation("scene")}
style={{ background: "white", marginRight: "3px" }}>
Scene
</button>
<button
onClick={() => handleEditorNavigation("story")}
style={{ background: "white", marginRight: "3px" }}>
Storytelling
</button>
<button
onClick={() => handleEditorNavigation("widgets")}
style={{ background: "white", marginRight: "3px" }}>
Widgets
</button>
<button
onClick={() => handleEditorNavigation("publish")}
style={{ background: "white", marginRight: "3px" }}>
Publish
</button>
</div>
</Wrapper>
);
};

export default Navbar;

const Wrapper = styled.div`
display: flex;
justify-content: space-between;
height: 53px;
background: #171618;
`;
12 changes: 12 additions & 0 deletions web/src/beta/features/RightPanel/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { styled } from "@reearth/services/theme";

const RightPanel: React.FC = () => {
return <Wrapper>RightPanel</Wrapper>;
};

export default RightPanel;

const Wrapper = styled.div`
background: #232226;
width: 235px;
`;
12 changes: 12 additions & 0 deletions web/src/beta/features/Visualizer/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { styled } from "@reearth/services/theme";

const Visualizer: React.FC = () => {
return <Wrapper>Visualizer</Wrapper>;
};

export default Visualizer;

const Wrapper = styled.div`
background: #3f3d45;
flex: 1;
`;
1 change: 1 addition & 0 deletions web/src/beta/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { useNavbarHooks } from "./navbarHooks";
19 changes: 19 additions & 0 deletions web/src/beta/hooks/navbarHooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { useCallback } from "react";
import { useNavigate } from "react-router-dom";

export type Tab = "scene" | "story" | "widgets" | "publish";

export const useNavbarHooks = ({ sceneId }: { sceneId?: string }) => {
const navigate = useNavigate();

const handleEditorNavigation = useCallback(
(tab: Tab) => {
navigate(tab !== "scene" ? `/scene/${sceneId}/${tab}` : "");
},
[sceneId, navigate],
);

return {
handleEditorNavigation,
};
};
62 changes: 62 additions & 0 deletions web/src/beta/pages/Editor/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { useEffect, useState } from "react";
import { useLocation } from "react-router-dom";

import LeftPanel from "@reearth/beta/features/LeftPanel";
import Navbar, { Tab } from "@reearth/beta/features/Navbar";
import RightPanel from "@reearth/beta/features/RightPanel";
import Visualizer from "@reearth/beta/features/Visualizer";
import { styled } from "@reearth/services/theme";

type Props = {};

const tabs = ["scene", "story", "widgets", "publish"];

const Editor: React.FC<Props> = () => {
const [sceneId, setSceneId] = useState<string | undefined>(undefined); // This will come from project query once beta project creation works
const [currentTab, setTab] = useState<Tab | undefined>();
const location = useLocation();

useEffect(() => {
const splitPathname = location.pathname.split("/");
KaWaite marked this conversation as resolved.
Show resolved Hide resolved
const tab =
splitPathname[
splitPathname.length === 4 ? splitPathname.length - 1 : splitPathname.length - 2
];
const sceneId =
splitPathname[
splitPathname.length === 4 ? splitPathname.length - 2 : splitPathname.length - 1
];

setSceneId(sceneId);

if (!tabs.includes(tab)) {
setTab("scene");
} else {
setTab(tab as Tab);
}
}, [location.pathname]);

return (
<Wrapper>
<Navbar sceneId={sceneId} currentTab={currentTab} />
<MainSection>
<LeftPanel />
<Visualizer />
<RightPanel />
</MainSection>
</Wrapper>
);
};

export default Editor;

const Wrapper = styled.div`
display: flex;
flex-direction: column;
height: 100%;
`;

const MainSection = styled.div`
display: flex;
flex: 1;
`;