diff --git a/webapp/app.ironcalc.com/frontend/src/components/FileBar.tsx b/webapp/app.ironcalc.com/frontend/src/components/FileBar.tsx
index 7e1ace0..4fe4ac8 100644
--- a/webapp/app.ironcalc.com/frontend/src/components/FileBar.tsx
+++ b/webapp/app.ironcalc.com/frontend/src/components/FileBar.tsx
@@ -1,7 +1,7 @@
import styled from "@emotion/styled";
import type { Model } from "@ironcalc/workbook";
import { IconButton, Tooltip } from "@mui/material";
-import { PanelLeftClose, PanelLeftOpen } from "lucide-react";
+import { CloudOff, PanelLeftClose, PanelLeftOpen } from "lucide-react";
import { useLayoutEffect, useRef, useState } from "react";
import { FileMenu } from "./FileMenu";
import { HelpMenu } from "./HelpMenu";
@@ -41,6 +41,9 @@ export function FileBar(properties: {
const [maxTitleWidth, setMaxTitleWidth] = useState(0);
const width = useWindowWidth();
+ const cloudWarningText1 = `This workbook is stored only in your browser. To keep it safe, download it as .xlsx.`;
+ const cloudWarningText2 = ` Future versions may be incompatible.`;
+
// biome-ignore lint/correctness/useExhaustiveDependencies: We need to update the maxTitleWidth when the width changes
useLayoutEffect(() => {
const el = spacerRef.current;
@@ -100,6 +103,49 @@ export function FileBar(properties: {
}}
maxWidth={maxTitleWidth}
/>
+
+ {cloudWarningText1}
+ {cloudWarningText2}
+
+ }
+ placement="bottom-start"
+ enterDelay={500}
+ slotProps={{
+ popper: {
+ modifiers: [
+ {
+ name: "offset",
+ options: {
+ offset: [0, -10],
+ },
+ },
+ ],
+ },
+ tooltip: {
+ sx: {
+ maxWidth: "240px",
+ fontSize: "11px",
+ padding: "8px",
+ backgroundColor: "#fff",
+ color: "#333333",
+ borderRadius: "8px",
+ border: "1px solid #e0e0e0",
+ boxShadow: "0px 1px 3px 0px #0000001A",
+ fontFamily: "Inter",
+ fontWeight: "400",
+ lineHeight: "16px",
+ },
+ },
+ }}
+ >
+
+
+
+
@@ -120,10 +166,35 @@ export function FileBar(properties: {
// so we need an absolute position
const WorkbookTitleWrapper = styled("div")`
position: absolute;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ gap: 6px;
left: 50%;
transform: translateX(-50%);
`;
+const CloudButton = styled("div")`
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: default;
+ background-color: transparent;
+ border-radius: 4px;
+ padding: 8px;
+ &:hover {
+ background-color: #f2f2f2;
+ }
+ &:active {
+ background-color: #e0e0e0;
+ }
+ svg {
+ width: 16px;
+ height: 16px;
+ color: #bdbdbd;
+ }
+`;
+
// The "Spacer" component occupies as much space as possible between the menu and the share button
const Spacer = styled("div")`
flex-grow: 1;
diff --git a/webapp/app.ironcalc.com/frontend/src/components/LeftDrawer/DrawerContent.tsx b/webapp/app.ironcalc.com/frontend/src/components/LeftDrawer/DrawerContent.tsx
index 807116d..b8a1196 100644
--- a/webapp/app.ironcalc.com/frontend/src/components/LeftDrawer/DrawerContent.tsx
+++ b/webapp/app.ironcalc.com/frontend/src/components/LeftDrawer/DrawerContent.tsx
@@ -1,4 +1,5 @@
import styled from "@emotion/styled";
+import LocalStorageAlert from "./LocalStorageAlert";
import WorkbookList from "./WorkbookList";
interface DrawerContentProps {
@@ -10,9 +11,14 @@ function DrawerContent(props: DrawerContentProps) {
const { setModel, onDelete } = props;
return (
-
-
-
+ <>
+
+
+
+
+
+
+ >
);
}
@@ -22,8 +28,17 @@ const ContentContainer = styled("div")`
gap: 4px;
padding: 16px 12px;
height: 100%;
- overflow: scroll;
+ overflow-y: auto;
+ overflow-x: hidden;
font-size: 12px;
`;
+const LocalStorageAlertWrapper = styled("div")`
+ position: absolute;
+ bottom: 56px;
+ left: 0;
+ right: 0;
+ padding: 12px;
+`;
+
export default DrawerContent;
diff --git a/webapp/app.ironcalc.com/frontend/src/components/LeftDrawer/LocalStorageAlert.tsx b/webapp/app.ironcalc.com/frontend/src/components/LeftDrawer/LocalStorageAlert.tsx
new file mode 100644
index 0000000..60d509d
--- /dev/null
+++ b/webapp/app.ironcalc.com/frontend/src/components/LeftDrawer/LocalStorageAlert.tsx
@@ -0,0 +1,111 @@
+import styled from "@emotion/styled";
+import { Alert } from "@mui/material";
+import { CircleAlert, X } from "lucide-react";
+import { useState } from "react";
+
+const ALERT_DISMISSED_KEY = "localStorageAlertDismissed";
+
+function LocalStorageAlert() {
+ const [isAlertVisible, setIsAlertVisible] = useState(
+ () => localStorage.getItem(ALERT_DISMISSED_KEY) !== "true",
+ );
+
+ const handleClose = () => {
+ setIsAlertVisible(false);
+ localStorage.setItem(ALERT_DISMISSED_KEY, "true");
+ };
+
+ if (!isAlertVisible) {
+ return null;
+ }
+
+ return (
+ }
+ action={
+
+
+
+ }
+ sx={{
+ padding: 0,
+ borderRadius: "8px",
+ backgroundColor: "rgba(255, 255, 255, 0.4)",
+ backdropFilter: "blur(10px)",
+ border: "1px solid #e0e0e0",
+ boxShadow: "0px 1px 3px 0px #0000001A",
+ fontFamily: "Inter",
+ fontWeight: "400",
+ lineHeight: "16px",
+ zIndex: 1,
+ }}
+ >
+ Heads up!
+
+ IronCalc stores your data only in your browser's local storage.
+
+
+ Download your XLSX often – future versions may not open
+ current workbooks, even if shared.
+
+
+ );
+}
+
+const AlertWrapper = styled(Alert)`
+ margin: 0;
+ .MuiAlert-message {
+ font-size: 11px;
+ padding: 12px 12px 12px 6px;
+ color: #333333;
+ }
+ .MuiAlert-icon {
+ height: 12px;
+ width: 12px;
+ color: #f2994a;
+ margin: 2px 0px 0px 8px;
+ padding: 6px 0px;
+ }
+`;
+
+const AlertTitle = styled("h2")`
+ font-size: 11px;
+ font-weight: 600;
+ line-height: 16px;
+ color: #333333;
+ margin: 0px 0px 4px 0px;
+`;
+
+const AlertBody = styled("p")`
+ font-weight: 400;
+ line-height: 16px;
+ margin: 0;
+`;
+
+const CloseButton = styled("button")`
+ position: absolute;
+ right: 4px;
+ top: 4px;
+ background: none;
+ border: none;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 4px;
+ color: #666666;
+ border-radius: 4px;
+ transition: background-color 0.2s;
+ svg {
+ width: 12px;
+ height: 12px;
+ }
+ &:hover {
+ background-color: #e0e0e0;
+ }
+ &:active {
+ background-color: #9e9e9e;
+ }
+`;
+
+export default LocalStorageAlert;