Files
SnapOtter/apps/web/src/components/editor/common/loading-overlay.tsx
T
SnapOtter 76501c4fb3 feat: add editor polish (mobile handling, loading states, accessibility)
- Show desktop-recommended message on mobile viewports (<768px)
- Add LoadingOverlay component for canvas loading/progress states
- Add ARIA tablist/tab/aria-selected to right panel tabs
- Add "Open in Editor" link in review panel after tool processing
2026-05-07 09:16:20 +08:00

56 lines
1.9 KiB
TypeScript

// apps/web/src/components/editor/common/loading-overlay.tsx
import { X } from "lucide-react";
import { cn } from "@/lib/utils";
import { useEditorStore } from "@/stores/editor-store";
export function LoadingOverlay() {
const loadingState = useEditorStore((s) => s.loadingState);
const setLoadingState = useEditorStore((s) => s.setLoadingState);
if (!loadingState) return null;
return (
<div className="absolute inset-0 z-50 flex items-center justify-center bg-background/60 backdrop-blur-sm">
<div className="flex flex-col items-center gap-3 p-6 rounded-xl bg-card border border-border shadow-lg min-w-[200px]">
{/* Operation name */}
<p className="text-sm font-medium text-foreground">{loadingState.operation}</p>
{/* Progress bar */}
{loadingState.progress !== null && (
<div className="w-full h-1.5 rounded-full bg-muted overflow-hidden">
<div
className={cn(
"h-full rounded-full bg-primary transition-all duration-200",
loadingState.progress < 0 && "animate-pulse w-full",
)}
style={
loadingState.progress >= 0
? { width: `${Math.min(100, loadingState.progress)}%` }
: undefined
}
/>
</div>
)}
{/* Indeterminate spinner when no progress */}
{loadingState.progress === null && (
<div className="w-5 h-5 border-2 border-muted border-t-primary rounded-full animate-spin" />
)}
{/* Cancel button */}
{loadingState.cancellable && (
<button
type="button"
onClick={() => setLoadingState(null)}
className="flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground mt-1"
aria-label="Cancel operation"
>
<X size={12} />
Cancel
</button>
)}
</div>
</div>
);
}