b6f89f9df0
- Resolve 57 merge conflicts from codebase restructure - Port dev feature code to new directory structure: * Update import paths to use @/ aliases * Add backward-compatible API signatures (createInstance, startInstance, deleteInstance) * Add missing type exports (ProjectWithRepos, InstanceHealth, Branch, BranchesResponse) * Extend Session and GitRepository types for dev features * Extend TerminalComponent props for mobile terminal wrapper * Add missing icon names (bell, drag, undo) Quality gates: tsc pass (0 errors), build pass, 127/131 tests pass (4 pre-existing failures unrelated to merge)
89 lines
2.2 KiB
TypeScript
89 lines
2.2 KiB
TypeScript
import { useEffect, useRef } from "react";
|
|
import { Icon } from "@/components/ui/Icon";
|
|
import type { IconName } from "@/components/ui/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>
|
|
);
|
|
}
|