Files
headquarter/apps/web/src/components/mobile-action-sheet.tsx
T
Fusion adaedb70ef feat: implement mobile app usability improvements
Mobile Navigation:
- Add MobileNav component with bottom tab bar
- Show mobile nav on small screens, hide desktop sidebar
- Add session count badge to Sessions tab
- Add safe area padding for notched devices

Session Management:
- Redesign SessionCard for mobile with action menu
- Add MobileActionSheet for session actions
- Keep primary action prominent

Forms & Dialogs:
- Stack form fields vertically on mobile
- Ensure 44px minimum touch targets
- Update dialogs for 320px viewport

Responsive Layout:
- Add MobilePageHeader with back button
- Reduce page padding on mobile
- Stack multi-column grids vertically

Touch & Interaction:
- Add active states to interactive elements
- Ensure 8px spacing between touch targets

Complex Pages:
- Update Repo Workspace for mobile
- Update Tool Workshop and Config Profiles

Build: TypeScript check passes, production build succeeds
2026-05-25 11:20:25 +02:00

89 lines
2.2 KiB
TypeScript

import { useEffect, useRef } from "react";
import { Icon } from "./icon";
import type { IconName } from "./icon";
export interface MobileActionSheetItem {
id: string;
label: string;
icon?: IconName;
variant?: "default" | "danger";
onClick: () => void;
}
interface MobileActionSheetProps {
isOpen: boolean;
onClose: () => void;
title: string;
actions: MobileActionSheetItem[];
}
export function MobileActionSheet({
isOpen,
onClose,
title,
actions,
}: MobileActionSheetProps) {
const sheetRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (isOpen) {
document.body.style.overflow = "hidden";
} else {
document.body.style.overflow = "";
}
return () => {
document.body.style.overflow = "";
};
}, [isOpen]);
useEffect(() => {
const handleEscape = (e: KeyboardEvent) => {
if (e.key === "Escape" && isOpen) {
onClose();
}
};
document.addEventListener("keydown", handleEscape);
return () => document.removeEventListener("keydown", handleEscape);
}, [isOpen, onClose]);
if (!isOpen) return null;
return (
<div className="mobile-action-sheet-overlay" onClick={onClose}>
<div
ref={sheetRef}
className="mobile-action-sheet"
onClick={(e) => e.stopPropagation()}
>
<div className="mobile-action-sheet-header">
<div className="mobile-action-sheet-handle" />
<h3>{title}</h3>
</div>
<div className="mobile-action-sheet-actions">
{actions.map((action) => (
<button
key={action.id}
className={`mobile-action-sheet-button ${action.variant || "default"}`}
onClick={() => {
action.onClick();
onClose();
}}
type="button"
>
{action.icon && <Icon name={action.icon} size="md" />}
<span>{action.label}</span>
</button>
))}
</div>
<button
className="mobile-action-sheet-cancel"
onClick={onClose}
type="button"
>
Cancel
</button>
</div>
</div>
);
}