update: show scroll arrows on narrow displays

This commit is contained in:
Daniel Gonzalez Albo
2025-10-06 23:29:04 +02:00
committed by Nicolás Hatcher Andrés
parent 7bcd978998
commit 6c27ae1355
2 changed files with 479 additions and 395 deletions

View File

@@ -14,6 +14,8 @@ import {
ArrowUpToLine, ArrowUpToLine,
Bold, Bold,
ChevronDown, ChevronDown,
ChevronLeft,
ChevronRight,
DecimalsArrowLeft, DecimalsArrowLeft,
DecimalsArrowRight, DecimalsArrowRight,
Euro, Euro,
@@ -36,7 +38,7 @@ import {
Undo2, Undo2,
WrapText, WrapText,
} from "lucide-react"; } from "lucide-react";
import { useRef, useState } from "react"; import { useCallback, useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { ArrowMiddleFromLine } from "../../icons"; import { ArrowMiddleFromLine } from "../../icons";
import { theme } from "../../theme"; import { theme } from "../../theme";
@@ -94,17 +96,51 @@ function Toolbar(properties: ToolbarProperties) {
const [fillColorPickerOpen, setFillColorPickerOpen] = useState(false); const [fillColorPickerOpen, setFillColorPickerOpen] = useState(false);
const [borderPickerOpen, setBorderPickerOpen] = useState(false); const [borderPickerOpen, setBorderPickerOpen] = useState(false);
const [nameManagerDialogOpen, setNameManagerDialogOpen] = useState(false); const [nameManagerDialogOpen, setNameManagerDialogOpen] = useState(false);
const [showLeftArrow, setShowLeftArrow] = useState(false);
const [showRightArrow, setShowRightArrow] = useState(false);
const fontColorButton = useRef(null); const fontColorButton = useRef(null);
const fillColorButton = useRef(null); const fillColorButton = useRef(null);
const borderButton = useRef(null); const borderButton = useRef(null);
const toolbarRef = useRef<HTMLDivElement>(null);
const { t } = useTranslation(); const { t } = useTranslation();
const { canEdit } = properties; const { canEdit } = properties;
const scrollLeft = () =>
toolbarRef.current?.scrollBy({ left: -200, behavior: "smooth" });
const scrollRight = () =>
toolbarRef.current?.scrollBy({ left: 200, behavior: "smooth" });
const updateArrows = useCallback(() => {
if (!toolbarRef.current) return;
const { scrollLeft, scrollWidth, clientWidth } = toolbarRef.current;
setShowLeftArrow(scrollLeft > 0);
setShowRightArrow(scrollLeft < scrollWidth - clientWidth);
}, []);
useEffect(() => {
const toolbar = toolbarRef.current;
if (!toolbar) return;
updateArrows();
toolbar.addEventListener("scroll", updateArrows);
return () => toolbar.removeEventListener("scroll", updateArrows);
}, [updateArrows]);
return ( return (
<ToolbarContainer> <ToolbarWrapper>
{showLeftArrow && (
<ScrollArrow
$direction="left"
onClick={scrollLeft}
title={t("toolbar.scroll_left")}
>
<ChevronLeft />
</ScrollArrow>
)}
<ToolbarContainer ref={toolbarRef}>
{/* History/Edit Group */} {/* History/Edit Group */}
<ButtonGroup> <ButtonGroup>
<StyledButton <StyledButton
@@ -514,23 +550,40 @@ function Toolbar(properties: ToolbarProperties) {
model={properties.nameManagerProperties} model={properties.nameManagerProperties}
/> />
</ToolbarContainer> </ToolbarContainer>
{showRightArrow && (
<ScrollArrow
$direction="right"
onClick={scrollRight}
title={t("toolbar.scroll_right")}
>
<ChevronRight />
</ScrollArrow>
)}
</ToolbarWrapper>
); );
} }
const ToolbarContainer = styled("div")` const ToolbarWrapper = styled("div")`
position: relative;
display: flex; display: flex;
flex-shrink: 0;
align-items: center; align-items: center;
background: ${({ theme }) => theme.palette.background.paper}; background: ${({ theme }) => theme.palette.background.paper};
height: ${TOOLBAR_HEIGHT}px; height: ${TOOLBAR_HEIGHT}px;
line-height: ${TOOLBAR_HEIGHT}px;
border-bottom: 1px solid ${({ theme }) => theme.palette.grey["300"]}; border-bottom: 1px solid ${({ theme }) => theme.palette.grey["300"]};
font-family: Inter;
border-radius: 4px 4px 0px 0px; border-radius: 4px 4px 0px 0px;
`;
const ToolbarContainer = styled("div")`
display: flex;
flex: 1;
align-items: center;
overflow-x: auto; overflow-x: auto;
padding: 0px 12px; padding: 0px 12px;
gap: 4px; gap: 4px;
scrollbar-width: none; scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
`; `;
type TypeButtonProperties = { $pressed: boolean }; type TypeButtonProperties = { $pressed: boolean };
@@ -617,4 +670,33 @@ const ButtonGroup = styled("div")({
gap: "4px", gap: "4px",
}); });
type ScrollArrowProps = { $direction: "left" | "right" };
const ScrollArrow = styled("button", {
shouldForwardProp: (prop) => prop !== "$direction",
})<ScrollArrowProps>(({ $direction }) => ({
position: "absolute",
top: "50%",
transform: "translateY(-50%)",
[$direction]: "0px",
zIndex: 10,
width: "24px",
height: "100%",
display: "flex",
alignItems: "center",
justifyContent: "center",
backgroundColor: "white",
border:
$direction === "left"
? `none; border-right: 1px solid ${theme.palette.grey["300"]};`
: `none; border-left: 1px solid ${theme.palette.grey["300"]};`,
cursor: "pointer",
"&:hover": {
backgroundColor: theme.palette.grey["100"],
},
svg: {
width: "16px",
height: "16px",
},
}));
export default Toolbar; export default Toolbar;

View File

@@ -27,6 +27,8 @@
"vertical_align_top": "Align top", "vertical_align_top": "Align top",
"selected_png": "Export Selected area as PNG", "selected_png": "Export Selected area as PNG",
"wrap_text": "Wrap text", "wrap_text": "Wrap text",
"scroll_left": "Scroll left",
"scroll_right": "Scroll right",
"format_menu": { "format_menu": {
"auto": "Auto", "auto": "Auto",
"number": "Number", "number": "Number",