update: Add a left drawer to improve workbook management (#453)
* update: add leftbar to app * style: a few cosmetic changes * update: allow pinning workbooks * style: show ellipsis button only on hover * update: add basic responsiveness * style: use active state when file and help menus are open * style: increase transition time * update: allow duplication of workbooks * chore: standardize menus
This commit is contained in:
committed by
GitHub
parent
dd4467f95d
commit
f2da24326b
@@ -2,6 +2,7 @@ import "./App.css";
|
||||
import styled from "@emotion/styled";
|
||||
import { useEffect, useState } from "react";
|
||||
import { FileBar } from "./components/FileBar";
|
||||
import LeftDrawer from "./components/LeftDrawer/LeftDrawer";
|
||||
import WelcomeDialog from "./components/WelcomeDialog/WelcomeDialog";
|
||||
import {
|
||||
get_documentation_model,
|
||||
@@ -10,6 +11,7 @@ import {
|
||||
} from "./components/rpc";
|
||||
import {
|
||||
createNewModel,
|
||||
deleteModelByUuid,
|
||||
deleteSelectedModel,
|
||||
isStorageEmpty,
|
||||
loadSelectedModelFromStorage,
|
||||
@@ -27,6 +29,7 @@ function App() {
|
||||
const [model, setModel] = useState<Model | null>(null);
|
||||
const [showWelcomeDialog, setShowWelcomeDialog] = useState(false);
|
||||
const [isTemplatesDialogOpen, setTemplatesDialogOpen] = useState(false);
|
||||
const [isDrawerOpen, setIsDrawerOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
async function start() {
|
||||
@@ -88,43 +91,71 @@ function App() {
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
// Handlers for model changes that also update our models state
|
||||
const handleNewModel = () => {
|
||||
const newModel = createNewModel();
|
||||
setModel(newModel);
|
||||
};
|
||||
|
||||
const handleSetModel = (uuid: string) => {
|
||||
const newModel = selectModelFromStorage(uuid);
|
||||
if (newModel) {
|
||||
setModel(newModel);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeleteModel = () => {
|
||||
const newModel = deleteSelectedModel();
|
||||
if (newModel) {
|
||||
setModel(newModel);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeleteModelByUuid = (uuid: string) => {
|
||||
const newModel = deleteModelByUuid(uuid);
|
||||
if (newModel) {
|
||||
setModel(newModel);
|
||||
}
|
||||
};
|
||||
|
||||
// We could use context for model, but the problem is that it should initialized to null.
|
||||
// Passing the property down makes sure it is always defined.
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<FileBar
|
||||
model={model}
|
||||
onModelUpload={async (arrayBuffer: ArrayBuffer, fileName: string) => {
|
||||
const blob = await uploadFile(arrayBuffer, fileName);
|
||||
|
||||
const bytes = new Uint8Array(await blob.arrayBuffer());
|
||||
const newModel = Model.from_bytes(bytes);
|
||||
saveModelToStorage(newModel);
|
||||
|
||||
setModel(newModel);
|
||||
}}
|
||||
newModel={() => {
|
||||
const createdModel = createNewModel();
|
||||
setModel(createdModel);
|
||||
}}
|
||||
newModelFromTemplate={() => {
|
||||
setTemplatesDialogOpen(true);
|
||||
}}
|
||||
setModel={(uuid: string) => {
|
||||
const newModel = selectModelFromStorage(uuid);
|
||||
if (newModel) {
|
||||
setModel(newModel);
|
||||
}
|
||||
}}
|
||||
onDelete={() => {
|
||||
const newModel = deleteSelectedModel();
|
||||
if (newModel) {
|
||||
setModel(newModel);
|
||||
}
|
||||
}}
|
||||
<LeftDrawer
|
||||
open={isDrawerOpen}
|
||||
onClose={() => setIsDrawerOpen(false)}
|
||||
newModel={handleNewModel}
|
||||
setModel={handleSetModel}
|
||||
onDelete={handleDeleteModelByUuid}
|
||||
/>
|
||||
<IronCalc model={model} />
|
||||
<MainContent isDrawerOpen={isDrawerOpen}>
|
||||
{isDrawerOpen && (
|
||||
<MobileOverlay onClick={() => setIsDrawerOpen(false)} />
|
||||
)}
|
||||
<FileBar
|
||||
model={model}
|
||||
onModelUpload={async (arrayBuffer: ArrayBuffer, fileName: string) => {
|
||||
const blob = await uploadFile(arrayBuffer, fileName);
|
||||
|
||||
const bytes = new Uint8Array(await blob.arrayBuffer());
|
||||
const newModel = Model.from_bytes(bytes);
|
||||
saveModelToStorage(newModel);
|
||||
|
||||
setModel(newModel);
|
||||
}}
|
||||
newModel={handleNewModel}
|
||||
newModelFromTemplate={() => {
|
||||
setTemplatesDialogOpen(true);
|
||||
}}
|
||||
setModel={handleSetModel}
|
||||
onDelete={handleDeleteModel}
|
||||
isDrawerOpen={isDrawerOpen}
|
||||
setIsDrawerOpen={setIsDrawerOpen}
|
||||
/>
|
||||
<IronCalc model={model} />
|
||||
</MainContent>
|
||||
{showWelcomeDialog && (
|
||||
<WelcomeDialog
|
||||
onClose={() => {
|
||||
@@ -175,13 +206,44 @@ function App() {
|
||||
}
|
||||
|
||||
const Wrapper = styled("div")`
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
`;
|
||||
|
||||
const MainContent = styled("div")<{ isDrawerOpen: boolean }>`
|
||||
margin-left: ${({ isDrawerOpen }) => (isDrawerOpen ? "0px" : "-264px")};
|
||||
transition: margin-left 0.2s;
|
||||
width: ${({ isDrawerOpen }) =>
|
||||
isDrawerOpen ? "calc(100% - 264px)" : "100%"};
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
|
||||
@media (max-width: 440px) {
|
||||
${({ isDrawerOpen }) =>
|
||||
isDrawerOpen &&
|
||||
`
|
||||
min-width: 440px;
|
||||
`}
|
||||
|
||||
`;
|
||||
|
||||
const MobileOverlay = styled("div")`
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
z-index: 1;
|
||||
cursor: pointer;
|
||||
|
||||
@media (min-width: 441px) {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const Loading = styled("div")`
|
||||
|
||||
Reference in New Issue
Block a user