feat: add mobile layout with chat panel at bottom (#109)

This commit is contained in:
Dayuan Jiang
2025-12-05 23:25:59 +09:00
committed by GitHub
parent 4e32a094b1
commit 7205896c8c
2 changed files with 54 additions and 62 deletions

View File

@@ -3,7 +3,6 @@ import React, { useState, useEffect, useRef } from "react";
import { DrawIoEmbed } from "react-drawio";
import ChatPanel from "@/components/chat-panel";
import { useDiagram } from "@/contexts/diagram-context";
import { Monitor } from "lucide-react";
import {
ResizablePanelGroup,
ResizablePanel,
@@ -74,29 +73,13 @@ export default function Home() {
return (
<div className="h-screen bg-background relative overflow-hidden">
{/* Mobile warning overlay */}
{isMobile && (
<div className="absolute inset-0 z-50 flex items-center justify-center bg-background">
<div className="text-center p-8 max-w-sm mx-auto animate-fade-in">
<div className="w-16 h-16 rounded-2xl bg-primary/10 flex items-center justify-center mx-auto mb-6">
<Monitor className="w-8 h-8 text-primary" />
</div>
<h1 className="text-xl font-semibold text-foreground mb-3">
Desktop Required
</h1>
<p className="text-sm text-muted-foreground leading-relaxed">
This application works best on desktop or laptop
devices. Please open it on a larger screen for the
full experience.
</p>
</div>
</div>
)}
<ResizablePanelGroup direction="horizontal" className="h-full">
<ResizablePanelGroup
direction={isMobile ? "vertical" : "horizontal"}
className="h-full"
>
{/* Draw.io Canvas */}
<ResizablePanel defaultSize={67} minSize={30}>
<div className="h-full relative p-2">
<ResizablePanel defaultSize={isMobile ? 50 : 67} minSize={20}>
<div className={`h-full relative ${isMobile ? "p-1" : "p-2"}`}>
<div className="h-full rounded-xl overflow-hidden shadow-soft-lg border border-border/30 bg-white">
<DrawIoEmbed
key={drawioUi}
@@ -119,15 +102,15 @@ export default function Home() {
{/* Chat Panel */}
<ResizablePanel
ref={chatPanelRef}
defaultSize={33}
minSize={15}
maxSize={50}
collapsible
collapsedSize={3}
defaultSize={isMobile ? 50 : 33}
minSize={isMobile ? 20 : 15}
maxSize={isMobile ? 80 : 50}
collapsible={!isMobile}
collapsedSize={isMobile ? 0 : 3}
onCollapse={() => setIsChatVisible(false)}
onExpand={() => setIsChatVisible(true)}
>
<div className="h-full py-2 pr-2">
<div className={`h-full ${isMobile ? "p-1" : "py-2 pr-2"}`}>
<ChatPanel
isVisible={isChatVisible}
onToggleVisibility={toggleChatPanel}
@@ -137,6 +120,7 @@ export default function Home() {
localStorage.setItem("drawio-theme", newTheme);
setDrawioUi(newTheme);
}}
isMobile={isMobile}
/>
</div>
</ResizablePanel>

View File

@@ -31,6 +31,7 @@ interface ChatPanelProps {
onToggleVisibility: () => void;
drawioUi: "min" | "sketch";
onToggleDrawioUi: () => void;
isMobile?: boolean;
}
export default function ChatPanel({
@@ -38,6 +39,7 @@ export default function ChatPanel({
onToggleVisibility,
drawioUi,
onToggleDrawioUi,
isMobile = false,
}: ChatPanelProps) {
const {
loadDiagram: onDisplayChart,
@@ -410,8 +412,8 @@ Please retry with an adjusted search pattern or use display_diagram if retries a
);
};
// Collapsed view
if (!isVisible) {
// Collapsed view (desktop only)
if (!isVisible && !isMobile) {
return (
<div className="h-full flex flex-col items-center pt-4 bg-card border border-border/30 rounded-xl">
<ButtonWithTooltip
@@ -445,35 +447,39 @@ Please retry with an adjusted search pattern or use display_diagram if retries a
style={{ position: "absolute" }}
/>
{/* Header */}
<header className="px-5 py-4 border-b border-border/50">
<header className={`${isMobile ? "px-3 py-2" : "px-5 py-4"} border-b border-border/50`}>
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="flex items-center gap-2">
<div className="flex items-center gap-2">
<Image
src="/favicon.ico"
alt="Next AI Drawio"
width={28}
height={28}
width={isMobile ? 24 : 28}
height={isMobile ? 24 : 28}
className="rounded"
/>
<h1 className="text-base font-semibold tracking-tight whitespace-nowrap">
<h1 className={`${isMobile ? "text-sm" : "text-base"} font-semibold tracking-tight whitespace-nowrap`}>
Next AI Drawio
</h1>
</div>
<Link
href="/about"
className="text-sm text-muted-foreground hover:text-foreground transition-colors ml-2"
>
About
</Link>
<ButtonWithTooltip
tooltipContent="Recent generation failures were caused by our AI provider's infrastructure issue, not the app code. After extensive debugging, I've switched providers and observed 6 hours of stability. If issues persist, please report on GitHub."
variant="ghost"
size="icon"
className="h-6 w-6 text-green-500 hover:text-green-600"
>
<CheckCircle className="h-4 w-4" />
</ButtonWithTooltip>
{!isMobile && (
<Link
href="/about"
className="text-sm text-muted-foreground hover:text-foreground transition-colors ml-2"
>
About
</Link>
)}
{!isMobile && (
<ButtonWithTooltip
tooltipContent="Recent generation failures were caused by our AI provider's infrastructure issue, not the app code. After extensive debugging, I've switched providers and observed 6 hours of stability. If issues persist, please report on GitHub."
variant="ghost"
size="icon"
className="h-6 w-6 text-green-500 hover:text-green-600"
>
<CheckCircle className="h-4 w-4" />
</ButtonWithTooltip>
)}
</div>
<div className="flex items-center gap-1">
<a
@@ -482,7 +488,7 @@ Please retry with an adjusted search pattern or use display_diagram if retries a
rel="noopener noreferrer"
className="p-2 rounded-lg text-muted-foreground hover:text-foreground hover:bg-accent transition-colors"
>
<FaGithub className="w-5 h-5" />
<FaGithub className={`${isMobile ? "w-4 h-4" : "w-5 h-5"}`} />
</a>
{accessCodeRequired && (
<ButtonWithTooltip
@@ -492,18 +498,20 @@ Please retry with an adjusted search pattern or use display_diagram if retries a
onClick={() => setShowSettingsDialog(true)}
className="hover:bg-accent"
>
<Settings className="h-5 w-5 text-muted-foreground" />
<Settings className={`${isMobile ? "h-4 w-4" : "h-5 w-5"} text-muted-foreground`} />
</ButtonWithTooltip>
)}
{!isMobile && (
<ButtonWithTooltip
tooltipContent="Hide chat panel (Ctrl+B)"
variant="ghost"
size="icon"
onClick={onToggleVisibility}
className="hover:bg-accent"
>
<PanelRightClose className="h-5 w-5 text-muted-foreground" />
</ButtonWithTooltip>
)}
<ButtonWithTooltip
tooltipContent="Hide chat panel (Ctrl+B)"
variant="ghost"
size="icon"
onClick={onToggleVisibility}
className="hover:bg-accent"
>
<PanelRightClose className="h-5 w-5 text-muted-foreground" />
</ButtonWithTooltip>
</div>
</div>
</header>
@@ -521,7 +529,7 @@ Please retry with an adjusted search pattern or use display_diagram if retries a
</main>
{/* Input */}
<footer className="p-4 border-t border-border/50 bg-card/50">
<footer className={`${isMobile ? "p-2" : "p-4"} border-t border-border/50 bg-card/50`}>
<ChatInput
input={input}
status={status}