On Android tablets/foldables in portrait, screen width can exceed 640px causing the desktop footer bar to show. Now use portrait orientation detection to force the mobile footer bar layout on Android regardless of screen width. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -17,6 +17,7 @@ const DesktopFooterBar: React.FC<FooterBarChildProps> = ({
|
||||
progressValid,
|
||||
progressFraction,
|
||||
navigationHandlers,
|
||||
isMobileLayout,
|
||||
onSpeakText,
|
||||
}) => {
|
||||
const _ = useTranslation();
|
||||
@@ -67,7 +68,11 @@ const DesktopFooterBar: React.FC<FooterBarChildProps> = ({
|
||||
|
||||
return (
|
||||
<div
|
||||
className='hidden h-8 w-full items-center gap-x-4 overflow-x-auto px-4 sm:flex'
|
||||
className={
|
||||
isMobileLayout
|
||||
? 'hidden'
|
||||
: 'hidden h-8 w-full items-center gap-x-4 overflow-x-auto px-4 sm:flex'
|
||||
}
|
||||
style={{
|
||||
bottom: isMobile ? `${gridInsets.bottom * 0.33}px` : '0px',
|
||||
scrollbarWidth: 'none',
|
||||
|
||||
@@ -194,6 +194,10 @@ const FooterBar: React.FC<FooterBarProps> = ({
|
||||
const footerBarRef = useRef<HTMLDivElement>(null);
|
||||
useSpatialNavigation(footerBarRef, isVisible);
|
||||
|
||||
const isPortrait = window.innerWidth <= window.innerHeight;
|
||||
const isMobile = appService?.isMobile || window.innerWidth < 640;
|
||||
const isMobileLayout = isMobile || (!!appService?.isAndroidApp && isPortrait);
|
||||
|
||||
const commonProps: FooterBarChildProps = {
|
||||
bookKey,
|
||||
gridInsets,
|
||||
@@ -201,6 +205,7 @@ const FooterBar: React.FC<FooterBarProps> = ({
|
||||
progressValid,
|
||||
progressFraction,
|
||||
navigationHandlers,
|
||||
isMobileLayout,
|
||||
onSetActionTab: handleSetActionTab,
|
||||
onSpeakText: handleSpeakText,
|
||||
};
|
||||
@@ -210,21 +215,24 @@ const FooterBar: React.FC<FooterBarProps> = ({
|
||||
(bookData?.isFixedLayout && viewSettings?.zoomLevel && viewSettings.zoomLevel > 100);
|
||||
|
||||
const containerClasses = clsx(
|
||||
'footer-bar shadow-xs bottom-0 left-0 z-10 flex w-full flex-col sm:h-[52px]',
|
||||
'sm:bg-base-100 border-base-300/50 border-t sm:border-none',
|
||||
'footer-bar shadow-xs bottom-0 left-0 z-10 flex w-full flex-col',
|
||||
isMobileLayout ? '' : 'sm:h-[52px]',
|
||||
isMobileLayout ? '' : 'sm:bg-base-100 sm:border-none',
|
||||
'border-base-300/50 border-t',
|
||||
'transition-[opacity,transform] duration-300',
|
||||
window.innerWidth < 640 ? 'fixed' : 'absolute',
|
||||
isMobileLayout ? 'fixed' : window.innerWidth < 640 ? 'fixed' : 'absolute',
|
||||
appService?.hasRoundedWindow && 'rounded-window-bottom-right',
|
||||
!isSideBarVisible && appService?.hasRoundedWindow && 'rounded-window-bottom-left',
|
||||
isHoveredAnim && 'hover-bar-anim',
|
||||
needHorizontalScroll ? 'sm:!bottom-3 sm:!h-10 sm:justify-end' : 'sm:justify-center',
|
||||
!isMobileLayout &&
|
||||
(needHorizontalScroll ? 'sm:!bottom-3 sm:!h-10 sm:justify-end' : 'sm:justify-center'),
|
||||
isVisible
|
||||
? 'pointer-events-auto translate-y-0 opacity-100'
|
||||
: 'pointer-events-none translate-y-full opacity-0 sm:translate-y-0',
|
||||
: isMobileLayout
|
||||
? 'pointer-events-none translate-y-full opacity-0'
|
||||
: 'pointer-events-none translate-y-full opacity-0 sm:translate-y-0',
|
||||
);
|
||||
|
||||
const isMobile = appService?.isMobile || window.innerWidth < 640;
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Hover trigger area */}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import clsx from 'clsx';
|
||||
import React from 'react';
|
||||
import { useResponsiveSize } from '@/hooks/useResponsiveSize';
|
||||
import { FooterBarChildProps } from './types';
|
||||
@@ -13,15 +14,16 @@ const MobileFooterBar: React.FC<FooterBarChildProps> = ({
|
||||
progressValid,
|
||||
progressFraction,
|
||||
navigationHandlers,
|
||||
isMobileLayout,
|
||||
onSetActionTab,
|
||||
}) => {
|
||||
const isMobile = window.innerWidth < 640 || window.innerHeight < 640;
|
||||
const isMobile = isMobileLayout || window.innerWidth < 640 || window.innerHeight < 640;
|
||||
const sliderHeight = useResponsiveSize(28);
|
||||
const marginIconSize = useResponsiveSize(20);
|
||||
const bottomOffset = isMobile ? `${gridInsets.bottom * 0.33 + 64}px` : '64px';
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={clsx(isMobileLayout && 'force-mobile-layout')}>
|
||||
<ColorPanel actionTab={actionTab} bottomOffset={bottomOffset} />
|
||||
<NavigationPanel
|
||||
bookKey={bookKey}
|
||||
@@ -42,9 +44,10 @@ const MobileFooterBar: React.FC<FooterBarChildProps> = ({
|
||||
bookKey={bookKey}
|
||||
actionTab={actionTab}
|
||||
gridInsets={gridInsets}
|
||||
isMobileLayout={isMobileLayout}
|
||||
onSetActionTab={onSetActionTab!}
|
||||
/>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ interface NavigationBarProps {
|
||||
bookKey: string;
|
||||
actionTab: string;
|
||||
gridInsets: Insets;
|
||||
isMobileLayout: boolean;
|
||||
onSetActionTab: (tab: string) => void;
|
||||
}
|
||||
|
||||
@@ -23,6 +24,7 @@ export const NavigationBar: React.FC<NavigationBarProps> = ({
|
||||
bookKey,
|
||||
actionTab,
|
||||
gridInsets,
|
||||
isMobileLayout,
|
||||
onSetActionTab,
|
||||
}) => {
|
||||
const isMobile = window.innerWidth < 640 || window.innerHeight < 640;
|
||||
@@ -36,7 +38,10 @@ export const NavigationBar: React.FC<NavigationBarProps> = ({
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx('bg-base-200 z-30 mt-auto flex w-full justify-between px-8 py-4 sm:hidden')}
|
||||
className={clsx(
|
||||
'bg-base-200 z-30 mt-auto flex w-full justify-between px-8 py-4',
|
||||
!isMobileLayout && 'sm:hidden',
|
||||
)}
|
||||
style={{
|
||||
paddingBottom: appService?.isAndroidApp
|
||||
? `calc(env(safe-area-inset-bottom) + 16px)`
|
||||
|
||||
@@ -27,6 +27,7 @@ export interface FooterBarChildProps {
|
||||
progressValid: boolean;
|
||||
gridInsets: Insets;
|
||||
actionTab: string;
|
||||
isMobileLayout: boolean;
|
||||
onSetActionTab: (tab: string) => void;
|
||||
onSpeakText: () => void;
|
||||
}
|
||||
|
||||
@@ -441,6 +441,13 @@ foliate-fxl {
|
||||
mask: linear-gradient(180deg, black 0%, rgba(0, 0, 0, 0.9) 50%, rgba(0, 0, 0, 0.5) 100%);
|
||||
}
|
||||
|
||||
/* Force mobile footer bar layout on Android portrait (overrides sm:hidden breakpoint) */
|
||||
@media (min-width: 640px) {
|
||||
.force-mobile-layout .sm\:hidden {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.visible-focus-inset-2:focus-visible {
|
||||
outline: none;
|
||||
box-shadow:
|
||||
|
||||
Reference in New Issue
Block a user