diff --git a/packages/inspector/src/App.css b/packages/inspector/src/App.css index 58c332f..f995cff 100644 --- a/packages/inspector/src/App.css +++ b/packages/inspector/src/App.css @@ -12,6 +12,26 @@ padding: 12px 20px; background: var(--bg-secondary); border-bottom: 1px solid var(--border-color); + gap: 12px; +} + +.mobile-menu-toggle { + display: none; + align-items: center; + justify-content: center; + width: 36px; + height: 36px; + padding: 0; + background: transparent; + border: 1px solid var(--border-color); + border-radius: 6px; + color: var(--text-primary); + cursor: pointer; + flex-shrink: 0; +} + +.mobile-menu-toggle:hover { + background: var(--bg-tertiary); } .header-brand { @@ -29,11 +49,13 @@ .header-brand h1 { font-size: 18px; font-weight: 600; + white-space: nowrap; } .header-status { display: flex; align-items: center; + margin-left: auto; } .status-badge { @@ -61,6 +83,7 @@ height: 8px; border-radius: 50%; background: currentColor; + flex-shrink: 0; } .status-badge.connected .status-dot { @@ -82,6 +105,11 @@ display: flex; flex: 1; overflow: hidden; + position: relative; +} + +.sidebar-overlay { + display: none; } .content { @@ -97,9 +125,47 @@ overflow: hidden; } -/* Responsive */ +/* Responsive - Tablet */ @media (max-width: 1200px) { .content-panels { flex-direction: column; } } + +/* Responsive - Mobile */ +@media (max-width: 768px) { + .header { + padding: 10px 16px; + } + + .mobile-menu-toggle { + display: flex; + } + + .header-brand h1 { + font-size: 16px; + } + + .status-text { + display: none; + } + + .status-badge { + padding: 6px; + } + + .sidebar-overlay { + display: block; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + z-index: 99; + } + + .content-panels { + flex-direction: column; + } +} diff --git a/packages/inspector/src/App.tsx b/packages/inspector/src/App.tsx index 5dc20a1..23527c5 100644 --- a/packages/inspector/src/App.tsx +++ b/packages/inspector/src/App.tsx @@ -1,4 +1,5 @@ import { useState, useCallback } from 'react' +import { Menu, X } from 'lucide-react' import { Sidebar } from './components/Sidebar' import { ToolsPanel } from './components/ToolsPanel' import { ResultsPane } from './components/ResultsPane' @@ -50,6 +51,7 @@ function App() { const [toolResult, setToolResult] = useState(null) const [isExecuting, setIsExecuting] = useState(false) const [lastExecution, setLastExecution] = useState<{ toolName: string; params: Record } | null>(null) + const [sidebarOpen, setSidebarOpen] = useState(false) const handleConnect = useCallback(async () => { if (isConnected) { @@ -93,6 +95,13 @@ function App() { return (
+
window.location.reload()}>

MCP UI Inspector

@@ -100,18 +109,24 @@ function App() { {isConnected ? ( - Connected + Connected ) : ( - Disconnected + Disconnected )}
+ {sidebarOpen && ( +
setSidebarOpen(false)} + /> + )} setSidebarOpen(false)} />
diff --git a/packages/inspector/src/components/Button.css b/packages/inspector/src/components/Button.css index b362286..3b23ade 100644 --- a/packages/inspector/src/components/Button.css +++ b/packages/inspector/src/components/Button.css @@ -59,3 +59,17 @@ transform: rotate(360deg); } } + +/* Mobile adjustments */ +@media (max-width: 768px) { + .btn { + padding: 10px 14px; + font-size: 14px; + min-height: 44px; + } + + .btn-ghost { + min-height: 36px; + padding: 6px; + } +} diff --git a/packages/inspector/src/components/ResultsPane.css b/packages/inspector/src/components/ResultsPane.css index c3eb856..c34e16e 100644 --- a/packages/inspector/src/components/ResultsPane.css +++ b/packages/inspector/src/components/ResultsPane.css @@ -2,7 +2,7 @@ flex: 1; display: flex; flex-direction: column; - min-width: 400px; + min-width: 300px; background: var(--bg-primary); } @@ -193,3 +193,53 @@ min-width: 0; } } + +/* Mobile styles */ +@media (max-width: 768px) { + .results-pane { + min-width: 0; + min-height: 300px; + } + + .results-pane .panel-header { + padding: 0 12px; + flex-wrap: wrap; + gap: 8px; + } + + .results-tabs { + flex-wrap: nowrap; + } + + .tab { + padding: 10px 12px; + font-size: 12px; + } + + .results-actions { + gap: 8px; + } + + .timestamp { + display: none; + } + + .results-loading, + .results-empty, + .results-error { + padding: 24px 16px; + } + + .results-error pre { + font-size: 11px; + padding: 10px 12px; + } + + .text-output { + padding: 12px; + } + + .text-output pre { + font-size: 12px; + } +} diff --git a/packages/inspector/src/components/Sidebar.css b/packages/inspector/src/components/Sidebar.css index 410c489..826fb39 100644 --- a/packages/inspector/src/components/Sidebar.css +++ b/packages/inspector/src/components/Sidebar.css @@ -8,6 +8,25 @@ overflow-y: auto; } +/* Mobile sidebar */ +@media (max-width: 768px) { + .sidebar { + position: fixed; + top: 0; + left: 0; + bottom: 0; + z-index: 100; + transform: translateX(-100%); + transition: transform 0.3s ease; + width: 85%; + max-width: 320px; + } + + .sidebar.open { + transform: translateX(0); + } +} + .sidebar-section { border-bottom: 1px solid var(--border-color); } diff --git a/packages/inspector/src/components/Sidebar.tsx b/packages/inspector/src/components/Sidebar.tsx index 62badae..f647c24 100644 --- a/packages/inspector/src/components/Sidebar.tsx +++ b/packages/inspector/src/components/Sidebar.tsx @@ -11,6 +11,8 @@ interface SidebarProps { isStateless: boolean onConnect: () => void error: string | null + isOpen?: boolean + onClose?: () => void } export function Sidebar({ @@ -21,10 +23,18 @@ export function Sidebar({ sessionId, isStateless, onConnect, - error + error, + isOpen, + onClose }: SidebarProps) { + const handleConnect = () => { + onConnect() + // Close sidebar on mobile after connecting + if (onClose) onClose() + } + return ( -