mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2025-12-30 20:06:30 +01:00
fix: improve mobile navigation and interaction
- Fix mobile view toggle buttons not working when clicked (use offsetWidth instead of clientWidth) - Add flag to prevent scroll handler interference during programmatic scrolls - Move Files button from header to bottom navigation bar - Add bottom navigation bar with All Tools, Automate, and Files buttons - Add RightRail to mobile workspace view - Auto-switch to Tools view when clicking All Tools or Automate in mobile - Style bottom bar buttons as full-width clickable areas with labels 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
d854497266
commit
5d77373ef8
@ -116,3 +116,43 @@
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.mobile-bottom-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
padding: 0.5rem;
|
||||
border-top: 1px solid var(--border-subtle);
|
||||
background: var(--bg-toolbar);
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.mobile-bottom-button {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.25rem;
|
||||
padding: 0.5rem;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--text-primary);
|
||||
cursor: pointer;
|
||||
border-radius: 0.5rem;
|
||||
transition: background 0.2s ease;
|
||||
}
|
||||
|
||||
.mobile-bottom-button:hover {
|
||||
background: var(--bg-hover, rgba(0, 0, 0, 0.05));
|
||||
}
|
||||
|
||||
.mobile-bottom-button:active {
|
||||
background: var(--bg-active, rgba(0, 0, 0, 0.1));
|
||||
}
|
||||
|
||||
.mobile-bottom-button-label {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useToolWorkflow } from "../contexts/ToolWorkflowContext";
|
||||
import { ActionIcon, Group, useMantineColorScheme } from "@mantine/core";
|
||||
import { Group, useMantineColorScheme } from "@mantine/core";
|
||||
import { useSidebarContext } from "../contexts/SidebarContext";
|
||||
import { useDocumentMeta } from "../hooks/useDocumentMeta";
|
||||
import { BASE_PATH, getBaseUrl } from "../constants/app";
|
||||
import { useMediaQuery } from "@mantine/hooks";
|
||||
import AppsIcon from '@mui/icons-material/AppsRounded';
|
||||
|
||||
import ToolPanel from "../components/tools/ToolPanel";
|
||||
import Workbench from "../components/layout/Workbench";
|
||||
@ -28,13 +29,14 @@ export default function HomePage() {
|
||||
|
||||
const { quickAccessRef } = sidebarRefs;
|
||||
|
||||
const { selectedTool, selectedToolKey } = useToolWorkflow();
|
||||
const { selectedTool, selectedToolKey, handleToolSelect, handleBackToTools } = useToolWorkflow();
|
||||
|
||||
const { openFilesModal } = useFilesModalContext();
|
||||
const { colorScheme } = useMantineColorScheme();
|
||||
const isMobile = useMediaQuery("(max-width: 1024px)");
|
||||
const sliderRef = useRef<HTMLDivElement | null>(null);
|
||||
const [activeMobileView, setActiveMobileView] = useState<MobileView>("tools");
|
||||
const isProgrammaticScroll = useRef(false);
|
||||
|
||||
const brandName = t("home.mobile.brandName", "Stirling");
|
||||
const brandAltText = t("home.mobile.brandAlt", "Stirling PDF logo");
|
||||
@ -50,8 +52,14 @@ export default function HomePage() {
|
||||
if (isMobile) {
|
||||
const container = sliderRef.current;
|
||||
if (container) {
|
||||
const offset = activeMobileView === "tools" ? 0 : container.clientWidth;
|
||||
isProgrammaticScroll.current = true;
|
||||
const offset = activeMobileView === "tools" ? 0 : container.offsetWidth;
|
||||
container.scrollTo({ left: offset, behavior: "smooth" });
|
||||
|
||||
// Re-enable scroll listener after animation completes
|
||||
setTimeout(() => {
|
||||
isProgrammaticScroll.current = false;
|
||||
}, 500);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -72,6 +80,10 @@ export default function HomePage() {
|
||||
let animationFrame = 0;
|
||||
|
||||
const handleScroll = () => {
|
||||
if (isProgrammaticScroll.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (animationFrame) {
|
||||
cancelAnimationFrame(animationFrame);
|
||||
}
|
||||
@ -118,14 +130,6 @@ export default function HomePage() {
|
||||
<img src={brandMarkSrc} alt={brandAltText} className="mobile-brand-mark" />
|
||||
<span className="mobile-brand-name">{brandName}</span>
|
||||
</div>
|
||||
<ActionIcon
|
||||
variant="subtle"
|
||||
size="md"
|
||||
aria-label={t('home.mobile.openFiles', 'Open files')}
|
||||
onClick={() => openFilesModal()}
|
||||
>
|
||||
<LocalIcon icon="folder-rounded" width="1.25rem" height="1.25rem" />
|
||||
</ActionIcon>
|
||||
</div>
|
||||
<div className="mobile-toggle-buttons" role="tablist" aria-label={t('home.mobile.viewSwitcher', 'Switch workspace view')}>
|
||||
<button
|
||||
@ -159,12 +163,49 @@ export default function HomePage() {
|
||||
</div>
|
||||
<div className="mobile-slide" aria-label={t('home.mobile.workbenchSlide', 'Workspace panel')}>
|
||||
<div className="mobile-slide-content">
|
||||
<div className="flex-1 min-h-0 flex flex-col">
|
||||
<div className="flex-1 min-h-0 flex">
|
||||
<Workbench />
|
||||
<RightRail />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mobile-bottom-bar">
|
||||
<button
|
||||
className="mobile-bottom-button"
|
||||
aria-label={t('quickAccess.allTools', 'All Tools')}
|
||||
onClick={() => {
|
||||
handleBackToTools();
|
||||
if (isMobile) {
|
||||
setActiveMobileView('tools');
|
||||
}
|
||||
}}
|
||||
>
|
||||
<AppsIcon sx={{ fontSize: '1.5rem' }} />
|
||||
<span className="mobile-bottom-button-label">{t('quickAccess.allTools', 'All Tools')}</span>
|
||||
</button>
|
||||
<button
|
||||
className="mobile-bottom-button"
|
||||
aria-label={t('quickAccess.automate', 'Automate')}
|
||||
onClick={() => {
|
||||
handleToolSelect('automate');
|
||||
if (isMobile) {
|
||||
setActiveMobileView('tools');
|
||||
}
|
||||
}}
|
||||
>
|
||||
<LocalIcon icon="automation-outline" width="1.5rem" height="1.5rem" />
|
||||
<span className="mobile-bottom-button-label">{t('quickAccess.automate', 'Automate')}</span>
|
||||
</button>
|
||||
<button
|
||||
className="mobile-bottom-button"
|
||||
aria-label={t('home.mobile.openFiles', 'Open files')}
|
||||
onClick={() => openFilesModal()}
|
||||
>
|
||||
<LocalIcon icon="folder-rounded" width="1.5rem" height="1.5rem" />
|
||||
<span className="mobile-bottom-button-label">{t('quickAccess.files', 'Files')}</span>
|
||||
</button>
|
||||
</div>
|
||||
<FileManager selectedTool={selectedTool as any /* FIX ME */} />
|
||||
</div>
|
||||
) : (
|
||||
|
||||
Loading…
Reference in New Issue
Block a user