update: use a different dialog for templates only
This commit is contained in:
committed by
Nicolás Hatcher Andrés
parent
49c3d1e03a
commit
7841abe2d2
@@ -24,7 +24,6 @@ import { IronCalc, IronCalcIcon, Model, init } from "@ironcalc/workbook";
|
|||||||
function App() {
|
function App() {
|
||||||
const [model, setModel] = useState<Model | null>(null);
|
const [model, setModel] = useState<Model | null>(null);
|
||||||
const [showWelcomeDialog, setShowWelcomeDialog] = useState(false);
|
const [showWelcomeDialog, setShowWelcomeDialog] = useState(false);
|
||||||
const [isTemplateOnlyDialog, setIsTemplateOnlyDialog] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function start() {
|
async function start() {
|
||||||
@@ -59,7 +58,6 @@ function App() {
|
|||||||
const newModel = loadSelectedModelFromStorage();
|
const newModel = loadSelectedModelFromStorage();
|
||||||
if (!newModel) {
|
if (!newModel) {
|
||||||
setShowWelcomeDialog(true);
|
setShowWelcomeDialog(true);
|
||||||
setIsTemplateOnlyDialog(false); // Full dialog for first-time usage
|
|
||||||
const createdModel = new Model("template", "en", "UTC");
|
const createdModel = new Model("template", "en", "UTC");
|
||||||
setModel(createdModel);
|
setModel(createdModel);
|
||||||
} else {
|
} else {
|
||||||
@@ -109,7 +107,6 @@ function App() {
|
|||||||
}}
|
}}
|
||||||
newModelFromTemplate={() => {
|
newModelFromTemplate={() => {
|
||||||
setShowWelcomeDialog(true);
|
setShowWelcomeDialog(true);
|
||||||
setIsTemplateOnlyDialog(true); // Template-only dialog for "New from template"
|
|
||||||
}}
|
}}
|
||||||
setModel={(uuid: string) => {
|
setModel={(uuid: string) => {
|
||||||
const newModel = selectModelFromStorage(uuid);
|
const newModel = selectModelFromStorage(uuid);
|
||||||
@@ -133,7 +130,6 @@ function App() {
|
|||||||
setModel(createdModel);
|
setModel(createdModel);
|
||||||
}
|
}
|
||||||
setShowWelcomeDialog(false);
|
setShowWelcomeDialog(false);
|
||||||
setIsTemplateOnlyDialog(false);
|
|
||||||
}}
|
}}
|
||||||
onSelectTemplate={async (templateId) => {
|
onSelectTemplate={async (templateId) => {
|
||||||
switch (templateId) {
|
switch (templateId) {
|
||||||
@@ -151,10 +147,7 @@ function App() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
setShowWelcomeDialog(false);
|
setShowWelcomeDialog(false);
|
||||||
setIsTemplateOnlyDialog(false);
|
|
||||||
}}
|
}}
|
||||||
showHeader={!isTemplateOnlyDialog}
|
|
||||||
showNewSection={!isTemplateOnlyDialog}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { Check, FileDown, FileUp, Plus, Table2, Trash2 } from "lucide-react";
|
|||||||
import { useRef, useState } from "react";
|
import { useRef, useState } from "react";
|
||||||
import DeleteWorkbookDialog from "./DeleteWorkbookDialog";
|
import DeleteWorkbookDialog from "./DeleteWorkbookDialog";
|
||||||
import UploadFileDialog from "./UploadFileDialog";
|
import UploadFileDialog from "./UploadFileDialog";
|
||||||
|
import TemplatesDialog from "./WelcomeDialog/TemplatesDialog";
|
||||||
import { getModelsMetadata, getSelectedUuid } from "./storage";
|
import { getModelsMetadata, getSelectedUuid } from "./storage";
|
||||||
|
|
||||||
export function FileMenu(props: {
|
export function FileMenu(props: {
|
||||||
@@ -21,7 +22,7 @@ export function FileMenu(props: {
|
|||||||
const uuids = Object.keys(models);
|
const uuids = Object.keys(models);
|
||||||
const selectedUuid = getSelectedUuid();
|
const selectedUuid = getSelectedUuid();
|
||||||
const [isDeleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
const [isDeleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
||||||
|
const [isTemplatesDialogOpen, setTemplatesDialogOpen] = useState(false);
|
||||||
const elements = [];
|
const elements = [];
|
||||||
for (const uuid of uuids) {
|
for (const uuid of uuids) {
|
||||||
elements.push(
|
elements.push(
|
||||||
@@ -97,7 +98,7 @@ export function FileMenu(props: {
|
|||||||
</MenuItemWrapper>
|
</MenuItemWrapper>
|
||||||
<MenuItemWrapper
|
<MenuItemWrapper
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
props.newModelFromTemplate();
|
setTemplatesDialogOpen(true);
|
||||||
setMenuOpen(false);
|
setMenuOpen(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -165,6 +166,17 @@ export function FileMenu(props: {
|
|||||||
workbookName={selectedUuid ? models[selectedUuid] : ""}
|
workbookName={selectedUuid ? models[selectedUuid] : ""}
|
||||||
/>
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
<Modal
|
||||||
|
open={isTemplatesDialogOpen}
|
||||||
|
onClose={() => setTemplatesDialogOpen(false)}
|
||||||
|
aria-labelledby="templates-dialog-title"
|
||||||
|
aria-describedby="templates-dialog-description"
|
||||||
|
>
|
||||||
|
<TemplatesDialog
|
||||||
|
onClose={() => setTemplatesDialogOpen(false)}
|
||||||
|
onSelectTemplate={props.newModelFromTemplate}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,145 @@
|
|||||||
|
import { Dialog, styled } from "@mui/material";
|
||||||
|
import { House, TicketsPlane, X } from "lucide-react";
|
||||||
|
import { useState } from "react";
|
||||||
|
import TemplatesListItem from "./TemplatesListItem";
|
||||||
|
|
||||||
|
function TemplatesDialog(properties: {
|
||||||
|
onClose: () => void;
|
||||||
|
onSelectTemplate: (templateId: string) => void;
|
||||||
|
}) {
|
||||||
|
const [selectedTemplate, setSelectedTemplate] = useState<string>("");
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
properties.onClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTemplateSelect = (templateId: string) => {
|
||||||
|
setSelectedTemplate(templateId);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DialogWrapper open={true} onClose={() => {}}>
|
||||||
|
<DialogHeader>
|
||||||
|
<span style={{ flexGrow: 2, marginLeft: 12 }}>Choose a template</span>
|
||||||
|
<Cross
|
||||||
|
style={{ marginRight: 12 }}
|
||||||
|
onClick={handleClose}
|
||||||
|
title="Close Dialog"
|
||||||
|
tabIndex={0}
|
||||||
|
onKeyDown={(event) => event.key === "Enter" && properties.onClose()}
|
||||||
|
>
|
||||||
|
<X />
|
||||||
|
</Cross>
|
||||||
|
</DialogHeader>
|
||||||
|
<DialogContent>
|
||||||
|
<TemplatesListWrapper>
|
||||||
|
<TemplatesListItem
|
||||||
|
title="Mortgage calculator"
|
||||||
|
description="Estimate payments, interest, and overall cost."
|
||||||
|
icon={<House />}
|
||||||
|
iconColor="#2F80ED"
|
||||||
|
active={selectedTemplate === "mortgage_calculator"}
|
||||||
|
onClick={() => handleTemplateSelect("mortgage_calculator")}
|
||||||
|
/>
|
||||||
|
<TemplatesListItem
|
||||||
|
title="Travel expenses tracker"
|
||||||
|
description="Track trip costs and stay on budget."
|
||||||
|
icon={<TicketsPlane />}
|
||||||
|
iconColor="#EB5757"
|
||||||
|
active={selectedTemplate === "travel_expenses_tracker"}
|
||||||
|
onClick={() => handleTemplateSelect("travel_expenses_tracker")}
|
||||||
|
/>
|
||||||
|
</TemplatesListWrapper>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogFooter>
|
||||||
|
<DialogFooterButton
|
||||||
|
onClick={() => properties.onSelectTemplate(selectedTemplate)}
|
||||||
|
>
|
||||||
|
Create workbook
|
||||||
|
</DialogFooterButton>
|
||||||
|
</DialogFooter>
|
||||||
|
</DialogWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const DialogWrapper = styled(Dialog)`
|
||||||
|
font-family: Inter;
|
||||||
|
.MuiDialog-paper {
|
||||||
|
width: 440px;
|
||||||
|
border-radius: 12px;
|
||||||
|
margin: 16px;
|
||||||
|
border: 1px solid #e0e0e0;
|
||||||
|
}
|
||||||
|
.MuiBackdrop-root {
|
||||||
|
background-color: rgba(0, 0, 0, 0.4);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const DialogHeader = styled("div")`
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border-bottom: 1px solid #e0e0e0;
|
||||||
|
height: 44px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
font-family: Inter;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Cross = styled("div")`
|
||||||
|
&:hover {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
display: flex;
|
||||||
|
border-radius: 4px;
|
||||||
|
min-height: 24px;
|
||||||
|
min-width: 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
svg {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
stroke-width: 1.5;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const DialogContent = styled("div")`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 16px;
|
||||||
|
max-height: 300px;
|
||||||
|
overflow: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const TemplatesListWrapper = styled("div")`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const DialogFooter = styled("div")`
|
||||||
|
border-top: 1px solid #e0e0e0;
|
||||||
|
padding: 16px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const DialogFooterButton = styled("button")`
|
||||||
|
background-color: #F2994A;
|
||||||
|
border: none;
|
||||||
|
color: #FFF;
|
||||||
|
padding: 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 12px;
|
||||||
|
font-family: Inter;
|
||||||
|
&:hover {
|
||||||
|
background-color: #D68742;
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
background-color: #D68742;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default TemplatesDialog;
|
||||||
@@ -7,12 +7,8 @@ import TemplatesListItem from "./TemplatesListItem";
|
|||||||
function WelcomeDialog(properties: {
|
function WelcomeDialog(properties: {
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onSelectTemplate: (templateId: string) => void;
|
onSelectTemplate: (templateId: string) => void;
|
||||||
showHeader: boolean;
|
|
||||||
showNewSection: boolean;
|
|
||||||
}) {
|
}) {
|
||||||
const [selectedTemplate, setSelectedTemplate] = useState<string>(
|
const [selectedTemplate, setSelectedTemplate] = useState<string>("blank");
|
||||||
properties.showNewSection ? "blank" : "mortgage_calculator",
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
properties.onClose();
|
properties.onClose();
|
||||||
@@ -24,7 +20,6 @@ function WelcomeDialog(properties: {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<DialogWrapper open={true} onClose={() => {}}>
|
<DialogWrapper open={true} onClose={() => {}}>
|
||||||
{properties.showHeader !== false ? (
|
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogHeaderTitleWrapper>
|
<DialogHeaderTitleWrapper>
|
||||||
<DialogHeaderLogoWrapper>
|
<DialogHeaderLogoWrapper>
|
||||||
@@ -44,23 +39,7 @@ function WelcomeDialog(properties: {
|
|||||||
<X />
|
<X />
|
||||||
</Cross>
|
</Cross>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
) : (
|
|
||||||
<AlternativeHeader>
|
|
||||||
<span style={{ flexGrow: 2, marginLeft: 12 }}>Choose a template</span>
|
|
||||||
<Cross
|
|
||||||
style={{ marginRight: 12 }}
|
|
||||||
onClick={handleClose}
|
|
||||||
title="Close Dialog"
|
|
||||||
tabIndex={0}
|
|
||||||
onKeyDown={(event) => event.key === "Enter" && properties.onClose()}
|
|
||||||
>
|
|
||||||
<X />
|
|
||||||
</Cross>
|
|
||||||
</AlternativeHeader>
|
|
||||||
)}
|
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
{properties.showNewSection !== false && (
|
|
||||||
<>
|
|
||||||
<ListTitle>New</ListTitle>
|
<ListTitle>New</ListTitle>
|
||||||
<TemplatesListWrapper>
|
<TemplatesListWrapper>
|
||||||
<TemplatesListItem
|
<TemplatesListItem
|
||||||
@@ -72,8 +51,6 @@ function WelcomeDialog(properties: {
|
|||||||
onClick={() => handleTemplateSelect("blank")}
|
onClick={() => handleTemplateSelect("blank")}
|
||||||
/>
|
/>
|
||||||
</TemplatesListWrapper>
|
</TemplatesListWrapper>
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<ListTitle>Templates</ListTitle>
|
<ListTitle>Templates</ListTitle>
|
||||||
<TemplatesListWrapper>
|
<TemplatesListWrapper>
|
||||||
<TemplatesListItem
|
<TemplatesListItem
|
||||||
@@ -231,14 +208,4 @@ const DialogFooterButton = styled("button")`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const AlternativeHeader = styled("div")`
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
border-bottom: 1px solid #e0e0e0;
|
|
||||||
height: 44px;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
font-family: Inter;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export default WelcomeDialog;
|
export default WelcomeDialog;
|
||||||
|
|||||||
Reference in New Issue
Block a user