diff --git a/src/components/Dialog.scss b/src/components/Dialog.scss
index 2668f694..1035cd3f 100644
--- a/src/components/Dialog.scss
+++ b/src/components/Dialog.scss
@@ -19,7 +19,7 @@
@media #{$media-query} {
.Dialog {
--metric: calc(var(--space-factor) * 4);
- --inset-left: #{"max(var(--metric), env(safe-area-inset-left))"};
+ --inset-left: #{"max(var(--metric), var(--sal))"};
--inset-right: #{"max(var(--metric), env(safe-area-inset-right))"};
}
.Dialog__title {
@@ -49,9 +49,9 @@
height: 100%;
box-sizing: border-box;
overflow-y: auto;
- padding-left: #{"max(calc(var(--padding) * var(--space-factor)), env(safe-area-inset-left))"};
- padding-right: #{"max(calc(var(--padding) * var(--space-factor)), env(safe-area-inset-right))"};
- padding-bottom: #{"max(calc(var(--padding) * var(--space-factor)), env(safe-area-inset-bottom))"};
+ padding-left: #{"max(calc(var(--padding) * var(--space-factor)), var(--sal))"};
+ padding-right: #{"max(calc(var(--padding) * var(--space-factor)), var(--sar))"};
+ padding-bottom: #{"max(calc(var(--padding) * var(--space-factor)), var(--sab))"};
}
.Dialog .Modal__close {
diff --git a/src/components/MobileMenu.tsx b/src/components/MobileMenu.tsx
index 89145c4e..67bda75c 100644
--- a/src/components/MobileMenu.tsx
+++ b/src/components/MobileMenu.tsx
@@ -13,6 +13,7 @@ import { calculateScrollCenter, getTargetElement } from "../scene";
import { SelectedShapeActions, ShapesSwitcher } from "./Actions";
import { Section } from "./Section";
import { RoomDialog } from "./RoomDialog";
+import { SCROLLBAR_WIDTH, SCROLLBAR_MARGIN } from "../scene/scrollbars";
type MobileMenuProps = {
appState: AppState;
@@ -37,45 +38,6 @@ export function MobileMenu({
}: MobileMenuProps) {
return (
<>
- {appState.openMenu === "canvas" ? (
-
-
-
- {actionManager.renderAction("loadScene")}
- {actionManager.renderAction("saveScene")}
- {exportButton}
- {actionManager.renderAction("clearCanvas")}
-
- {actionManager.renderAction("changeViewBackgroundColor")}
-
-
-
-
- ) : appState.openMenu === "shape" &&
- showSelectedShapeActions(appState, elements) ? (
-
- ) : null}
{heading => (
@@ -98,26 +60,74 @@ export function MobileMenu({
-
+
+
+ {appState.openMenu === "canvas" ? (
+
+
+
+ {actionManager.renderAction("loadScene")}
+ {actionManager.renderAction("saveScene")}
+ {exportButton}
+ {actionManager.renderAction("clearCanvas")}
+
+ {actionManager.renderAction("changeViewBackgroundColor")}
+
+
+
+
+ ) : appState.openMenu === "shape" &&
+ showSelectedShapeActions(appState, elements) ? (
+
+ ) : null}
+
+
+
>
);
}
diff --git a/src/components/ToolIcon.scss b/src/components/ToolIcon.scss
index 30308aba..2446509d 100644
--- a/src/components/ToolIcon.scss
+++ b/src/components/ToolIcon.scss
@@ -39,6 +39,7 @@
.ToolIcon__label {
font-family: var(--ui-font);
margin: 0 0.8em;
+ text-overflow: ellipsis;
}
.ToolIcon_size_s .ToolIcon__icon {
diff --git a/src/locales/en.json b/src/locales/en.json
index f1bb77dc..109c6fe7 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -66,7 +66,7 @@
"edit": "Edit",
"undo": "Undo",
"redo": "Redo",
- "roomDialog": "Share a live-collaboration session",
+ "roomDialog": "Start live collaboration",
"createNewRoom": "Create new room"
},
"alerts": {
diff --git a/src/scene/scrollbars.ts b/src/scene/scrollbars.ts
index 6af637f3..48199719 100644
--- a/src/scene/scrollbars.ts
+++ b/src/scene/scrollbars.ts
@@ -2,8 +2,9 @@ import { ExcalidrawElement } from "../element/types";
import { getCommonBounds } from "../element";
import { FlooredNumber } from "../types";
import { ScrollBars } from "./types";
+import { getGlobalCSSVariable } from "../utils";
-const SCROLLBAR_MARGIN = 4;
+export const SCROLLBAR_MARGIN = 4;
export const SCROLLBAR_WIDTH = 6;
export const SCROLLBAR_COLOR = "rgba(0,0,0,0.3)";
@@ -36,11 +37,18 @@ export function getScrollBars(
const viewportWidthDiff = viewportWidth - viewportWidthWithZoom;
const viewportHeightDiff = viewportHeight - viewportHeightWithZoom;
+ const safeArea = {
+ top: parseInt(getGlobalCSSVariable("sat")),
+ bottom: parseInt(getGlobalCSSVariable("sab")),
+ left: parseInt(getGlobalCSSVariable("sal")),
+ right: parseInt(getGlobalCSSVariable("sar")),
+ };
+
// The viewport is the rectangle currently visible for the user
- const viewportMinX = -scrollX + viewportWidthDiff / 2;
- const viewportMinY = -scrollY + viewportHeightDiff / 2;
- const viewportMaxX = viewportMinX + viewportWidthWithZoom;
- const viewportMaxY = viewportMinY + viewportHeightWithZoom;
+ const viewportMinX = -scrollX + viewportWidthDiff / 2 + safeArea.left;
+ const viewportMinY = -scrollY + viewportHeightDiff / 2 + safeArea.top;
+ const viewportMaxX = viewportMinX + viewportWidthWithZoom - safeArea.right;
+ const viewportMaxY = viewportMinY + viewportHeightWithZoom - safeArea.bottom;
// The scene is the bounding box of both the elements and viewport
const sceneMinX = Math.min(elementsMinX, viewportMinX);
@@ -56,30 +64,36 @@ export function getScrollBars(
? null
: {
x:
+ Math.max(safeArea.left, SCROLLBAR_MARGIN) +
((viewportMinX - sceneMinX) / (sceneMaxX - sceneMinX)) *
- viewportWidth +
- SCROLLBAR_MARGIN,
- y: viewportHeight - SCROLLBAR_WIDTH - SCROLLBAR_MARGIN,
+ viewportWidth,
+ y:
+ viewportHeight -
+ SCROLLBAR_WIDTH -
+ Math.max(SCROLLBAR_MARGIN, safeArea.bottom),
width:
((viewportMaxX - viewportMinX) / (sceneMaxX - sceneMinX)) *
viewportWidth -
- SCROLLBAR_MARGIN * 2,
+ Math.max(SCROLLBAR_MARGIN * 2, safeArea.left + safeArea.right),
height: SCROLLBAR_WIDTH,
},
vertical:
viewportMinY === sceneMinY && viewportMaxY === sceneMaxY
? null
: {
- x: viewportWidth - SCROLLBAR_WIDTH - SCROLLBAR_MARGIN,
+ x:
+ viewportWidth -
+ SCROLLBAR_WIDTH -
+ Math.max(safeArea.right, SCROLLBAR_MARGIN),
y:
((viewportMinY - sceneMinY) / (sceneMaxY - sceneMinY)) *
viewportHeight +
- SCROLLBAR_MARGIN,
+ Math.max(safeArea.top, SCROLLBAR_MARGIN),
width: SCROLLBAR_WIDTH,
height:
((viewportMaxY - viewportMinY) / (sceneMaxY - sceneMinY)) *
viewportHeight -
- SCROLLBAR_MARGIN * 2,
+ Math.max(SCROLLBAR_MARGIN * 2, safeArea.top + safeArea.bottom),
},
};
}
diff --git a/src/styles.scss b/src/styles.scss
index 3885ab60..1541e79a 100644
--- a/src/styles.scss
+++ b/src/styles.scss
@@ -1,6 +1,13 @@
@import "./theme.css";
@import "./_variables";
+:root {
+ --sat: env(safe-area-inset-top);
+ --sab: env(safe-area-inset-bottom);
+ --sal: env(safe-area-inset-left);
+ --sar: env(safe-area-inset-right);
+}
+
body {
margin: 0;
--ui-font: Arial, Helvetica, sans-serif;
@@ -119,6 +126,7 @@ button,
cursor: pointer;
&:focus {
+ outline: transparent;
box-shadow: 0 0 0 2px #a5d8ff;
}
@@ -146,24 +154,38 @@ button,
}
}
-.App-toolbar,
-.App-mobile-menu {
- --spacing: 0.5rem;
- --padding: calc(4 * var(--space-factor));
- padding: var(--padding);
- padding-left: #{"max(var(--padding), env(safe-area-inset-left))"};
- padding-right: #{"max(var(--padding), env(safe-area-inset-right))"};
- background: #fcfcfc;
- border-top: 1px solid #ccc;
- box-sizing: border-box;
-}
-.App-toolbar {
- padding-bottom: #{"max(var(--padding), env(safe-area-inset-bottom))"};
- width: 100%;
- box-sizing: border-box;
- overflow: auto;
+.App-bottom-bar {
position: absolute;
+ top: 0;
bottom: 0;
+ left: 0;
+ right: 0;
+ --bar-padding: calc(4 * var(--space-factor));
+ padding-top: #{"max(var(--bar-padding), var(--sat))"};
+ padding-left: var(--sal);
+ padding-right: var(--sar);
+ padding-bottom: var(--sab);
+ z-index: 4;
+ display: flex;
+ align-items: flex-end;
+ pointer-events: none;
+
+ > .Island {
+ width: 100%;
+ max-width: 100%;
+ min-width: 100%;
+ box-sizing: border-box;
+ max-height: 100%;
+ display: flex;
+ flex-direction: column;
+ pointer-events: initial;
+ }
+}
+
+.App-toolbar {
+ width: 100%;
+
+ box-sizing: border-box;
}
.App-toolbar-content {
display: flex;
@@ -171,18 +193,11 @@ button,
justify-content: space-between;
}
.App-mobile-menu {
- --bottom: calc(3rem - 1px + max(var(--padding), env(safe-area-inset-bottom)));
- display: grid;
- position: fixed;
width: 100%;
- bottom: var(--bottom);
- z-index: 4;
- max-height: calc(100% - var(--bottom));
- overflow-y: scroll;
-}
-.App-mobile-menu .App-mobile-menu-scroller {
- background: #fcfcfc;
- box-shadow: none;
+ overflow-x: visible;
+ overflow-y: auto;
+ box-sizing: border-box;
+ margin-bottom: var(--bar-padding);
}
.App-menu {
@@ -358,6 +373,7 @@ button,
bottom: 30px;
transform: translateX(-50%);
padding: 10px 20px;
+ z-index: -1;
}
@media #{$media-query} {
@@ -366,6 +382,6 @@ button,
}
.scroll-back-to-content {
bottom: 80px;
- bottom: calc(80px + env(safe-area-inset-bottom));
+ bottom: calc(80px + var(--sab));
}
}
diff --git a/src/utils.ts b/src/utils.ts
index 7fb16485..9bc90f1e 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -194,3 +194,9 @@ export function sceneCoordsToViewportCoords(
return { x, y };
}
+
+export function getGlobalCSSVariable(name: string) {
+ return getComputedStyle(document.documentElement).getPropertyValue(
+ `--${name}`,
+ );
+}