All tests run on an 8-year-old MacBook Air.
The first version of HiyokoLogcat's AI diagnosis UI was a fixed panel at the bottom of the screen.
It took up 30% of the vertical space — permanently. Even when you weren't using AI. Users hated it.
The second version: a full-screen overlay that appears on demand and disappears with ESC. Here's why it works better and how I built it.
The problem with fixed panels
A fixed AI panel makes a promise: "AI is always here." But most of the time, you're reading logs, not diagnosing them.
30% of screen space dedicated to a feature you use 10% of the time is a bad trade.
The overlay model makes a different promise: "AI appears when you need it and gets out of the way when you don't."
The React overlay
interface DiagnosisOverlayProps {
isVisible: boolean;
result: string;
isLoading: boolean;
onClose: () => void;
}
export function DiagnosisOverlay({
isVisible, result, isLoading, onClose
}: DiagnosisOverlayProps) {
// Close on ESC key
useEffect(() => {
const handleKey = (e: KeyboardEvent) => {
if (e.key === 'Escape') onClose();
};
if (isVisible) {
window.addEventListener('keydown', handleKey);
}
return () => window.removeEventListener('keydown', handleKey);
}, [isVisible, onClose]);
if (!isVisible) return null;
return (
{
if (e.target === e.currentTarget) onClose();
}}
>
✕
{isLoading ? (
🐥 診断中...
) : (
{result}
)}
);
}
Click the backdrop → close. Press ESC → close. Click X → close. Three ways out, none of them surprising.
The loading state
Gemini takes 2–6 seconds. The overlay needs to communicate that something is happening:
.loading {
display: flex;
align-items: center;
gap: 8px;
animation: pulse 1.5s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.4; }
}
A pulsing "diagnosing..." indicator. Simple. Users know the app is working.
Preserving the last result
Don't clear the diagnosis when the overlay closes. If the user closes it and re-opens it, they should see the same result without waiting for another API call:
const [lastResult, setLastResult] = useState('');
const [isOverlayOpen, setIsOverlayOpen] = useState(false);
const handleDiagnose = async (logLine: LogLine) => {
setIsOverlayOpen(true);
setIsLoading(true);
const result = await diagnose(logLine);
setLastResult(result);
setIsLoading(false);
};
The result persists until a new diagnosis is requested. Closes and reopens instantly.
The lesson
UI for AI features should follow the same principles as any other UI: take up space proportional to how often the feature is used, and get out of the way when it's not.
An overlay that appears on demand beats a permanent panel every time.
HiyokoLogcat is free and open source → github.com/hiyoyok/HiyokoLogcat
X → @hiyoyok
Top comments (0)