bigger buttons, smaller gaps

This commit is contained in:
Ryan Di
2025-09-22 23:00:34 +10:00
parent b6b52018db
commit a67acf397d
10 changed files with 81 additions and 45 deletions

View File

@@ -111,8 +111,8 @@
--default-button-size: 2rem;
.compact-action-button {
width: 1.625rem;
height: 1.625rem;
width: var(--mobile-action-button-size);
height: var(--mobile-action-button-size);
border: none;
border-radius: var(--border-radius-lg);
color: var(--color-on-surface);
@@ -166,8 +166,8 @@
.ToolIcon {
.ToolIcon__icon {
width: 1.625rem;
height: 1.625rem;
width: 2.5rem;
height: 2.5rem;
&:hover {
background-color: transparent;

View File

@@ -900,11 +900,11 @@ export const MobileShapeActions = ({
const width = mobileActionsRef.current?.getBoundingClientRect()?.width ?? 0;
const WIDTH = 26;
const GAP = 8;
const WIDTH = 36;
const GAP = 6;
// max 6 actions + undo
const MIN_WIDTH = 7 * WIDTH + 6 * GAP;
// max 7 actions + undo
const MIN_WIDTH = 8 * WIDTH + 7 * GAP;
const ADDITIONAL_WIDTH = WIDTH + GAP;
@@ -921,7 +921,8 @@ export const MobileShapeActions = ({
padding: 0,
zIndex: 2,
backgroundColor: "transparent",
height: WIDTH * 1.75,
height: WIDTH * 1.25,
marginBottom: 2,
alignItems: "center",
gap: GAP,
pointerEvents: "none",

View File

@@ -163,6 +163,11 @@
width: 1.625rem;
height: 1.625rem;
}
&.compact-sizing {
width: var(--mobile-action-button-size);
height: var(--mobile-action-button-size);
}
}
.color-picker__button__hotkey-label {

View File

@@ -264,6 +264,7 @@ const ColorPickerTrigger = ({
"is-transparent": !color || color === "transparent",
"has-outline":
!color || !isColorDark(color, COLOR_OUTLINE_CONTRAST_THRESHOLD),
"compact-sizing": compactMode,
})}
aria-label={label}
style={color ? { "--swatch-color": color } : undefined}

View File

@@ -26,8 +26,8 @@ export const FontPickerTrigger = ({
background: "rgba(255, 255, 255, 0.1)",
backdropFilter: "blur(20px)",
WebkitBackdropFilter: "blur(20px)",
width: "1.625rem",
height: "1.625rem",
width: "2.25rem",
height: "2.25rem",
}
: {};

View File

@@ -13,14 +13,7 @@
scrollbar-width: none;
-ms-overflow-style: none;
justify-content: space-between;
@media screen and (min-width: 340px) {
gap: 6px;
}
@media screen and (min-width: 380px) {
gap: 8px;
}
position: relative;
}
.mobile-toolbar::-webkit-scrollbar {
@@ -37,8 +30,8 @@
flex-shrink: 0;
.ToolIcon__icon {
width: 2rem;
height: 2rem;
width: var(--mobile-action-button-size);
height: var(--mobile-action-button-size);
&:hover {
background-color: transparent;

View File

@@ -1,4 +1,4 @@
import { useState, useEffect } from "react";
import { useState, useEffect, useRef } from "react";
import clsx from "clsx";
import { KEYS, capitalizeString } from "@excalidraw/common";
@@ -101,6 +101,8 @@ export const MobileToolBar = ({
"arrow" | "line"
>("arrow");
const toolbarRef = useRef<HTMLDivElement>(null);
// keep lastActiveGenericShape in sync with active tool if user switches via other UI
useEffect(() => {
if (
@@ -141,8 +143,19 @@ export const MobileToolBar = ({
}
};
const showTextToolOutside = appState.width >= 400;
const showFrameToolOutside = appState.width >= 440;
const toolbarWidth =
toolbarRef.current?.getBoundingClientRect()?.width ?? 0 - 8;
const WIDTH = 36;
const GAP = 4;
// hand, selection, freedraw, eraser, rectangle, arrow, others
const MIN_TOOLS = 7;
const MIN_WIDTH = MIN_TOOLS * WIDTH + (MIN_TOOLS - 1) * GAP;
const ADDITIONAL_WIDTH = WIDTH + GAP;
const showImageToolOutside = toolbarWidth >= MIN_WIDTH + 1 * ADDITIONAL_WIDTH;
const showTextToolOutside = toolbarWidth >= MIN_WIDTH + 2 * ADDITIONAL_WIDTH;
const showFrameToolOutside = toolbarWidth >= MIN_WIDTH + 3 * ADDITIONAL_WIDTH;
const extraTools = [
"text",
@@ -175,7 +188,7 @@ export const MobileToolBar = ({
: extraToolsIcon;
return (
<div className="mobile-toolbar">
<div className="mobile-toolbar" ref={toolbarRef}>
{/* Hand Tool */}
<HandButton
checked={isHandToolActive(appState)}
@@ -243,7 +256,6 @@ export const MobileToolBar = ({
options={SHAPE_TOOLS}
activeTool={activeTool}
defaultOption={lastActiveGenericShape}
className="Shape"
namePrefix="shapeType"
title={capitalizeString(
t(
@@ -274,7 +286,6 @@ export const MobileToolBar = ({
options={LINEAR_ELEMENT_TOOLS}
activeTool={activeTool}
defaultOption={lastActiveLinearElement}
className="LinearElement"
namePrefix="linearElementType"
title={capitalizeString(
t(
@@ -298,19 +309,21 @@ export const MobileToolBar = ({
/>
{/* Image */}
<ToolButton
className={clsx({
active: activeTool.type === "image",
})}
type="radio"
icon={ImageIcon}
checked={activeTool.type === "image"}
name="editor-current-shape"
title={`${capitalizeString(t("toolBar.image"))}`}
aria-label={capitalizeString(t("toolBar.image"))}
data-testid="toolbar-image"
onChange={() => handleToolChange("image")}
/>
{showImageToolOutside && (
<ToolButton
className={clsx({
active: activeTool.type === "image",
})}
type="radio"
icon={ImageIcon}
checked={activeTool.type === "image"}
name="editor-current-shape"
title={`${capitalizeString(t("toolBar.image"))}`}
aria-label={capitalizeString(t("toolBar.image"))}
data-testid="toolbar-image"
onChange={() => handleToolChange("image")}
/>
)}
{/* Text Tool */}
{showTextToolOutside && (
@@ -347,13 +360,33 @@ export const MobileToolBar = ({
{/* Other Shapes */}
<DropdownMenu open={isOtherShapesMenuOpen} placement="top">
<DropdownMenu.Trigger
className={clsx("App-toolbar__extra-tools-trigger", {
"App-toolbar__extra-tools-trigger--selected": extraToolSelected,
})}
className={clsx(
"App-toolbar__extra-tools-trigger App-toolbar__extra-tools-trigger--mobile",
{
"App-toolbar__extra-tools-trigger--selected": extraToolSelected,
},
)}
onToggle={() => setIsOtherShapesMenuOpen(!isOtherShapesMenuOpen)}
title={t("toolBar.extraTools")}
style={{
width: WIDTH,
height: WIDTH,
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
{extraIcon}
<div
style={{
width: WIDTH,
height: WIDTH,
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
{extraIcon}
</div>
</DropdownMenu.Trigger>
<DropdownMenu.Content
onClickOutside={() => setIsOtherShapesMenuOpen(false)}

View File

@@ -501,7 +501,7 @@ body.excalidraw-cursor-resize * {
display: none;
}
.scroll-back-to-content {
bottom: calc(80px + var(--sab, 0));
bottom: calc(100px + var(--sab, 0));
z-index: -1;
}
}

View File

@@ -42,6 +42,7 @@
--lg-button-size: 2.25rem;
--lg-icon-size: 1rem;
--editor-container-padding: 1rem;
--mobile-action-button-size: 2.25rem;
@include isMobile {
--editor-container-padding: 0.75rem;

View File

@@ -183,6 +183,8 @@
border: none;
box-shadow: 0 0 0 1px var(--color-surface-lowest);
background-color: var(--color-surface-low);
width: var(--moobile-action-button-size, 2.25rem);
height: var(--moobile-action-button-size, 2.25rem);
&:active {
box-shadow: 0 0 0 1px var(--color-brand-active);