Make space for windows controls (#635)

This commit is contained in:
Will Chen
2025-07-11 16:28:13 -07:00
committed by GitHub
parent e539cbefdd
commit be1321152e
2 changed files with 149 additions and 97 deletions

View File

@@ -78,13 +78,13 @@ export const TitleBar = () => {
return ( return (
<> <>
<div className="@container z-11 w-full h-11 bg-(--sidebar) absolute top-0 left-0 app-region-drag flex items-center"> <div className="@container z-11 w-full h-11 bg-(--sidebar) absolute top-0 left-0 app-region-drag flex items-center">
<div className="pl-20"></div> <div className="pl-18"></div>
<img src={logo} alt="Dyad Logo" className="w-6 h-6 mr-2" /> <img src={logo} alt="Dyad Logo" className="w-6 h-6 mr-0.5" />
<Button <Button
data-testid="title-bar-app-name-button" data-testid="title-bar-app-name-button"
variant="outline" variant="outline"
size="sm" size="sm"
className={`hidden @md:block no-app-region-drag text-sm font-medium ${ className={`hidden @2xl:block no-app-region-drag text-xs max-w-38 truncate font-medium ${
selectedApp ? "cursor-pointer" : "" selectedApp ? "cursor-pointer" : ""
}`} }`}
onClick={handleAppClick} onClick={handleAppClick}
@@ -210,13 +210,15 @@ export function DyadProButton({
}} }}
variant="outline" variant="outline"
className={cn( className={cn(
"ml-4 no-app-region-drag h-7 bg-indigo-600 text-white dark:bg-indigo-600 dark:text-white", "hidden @2xl:block ml-1 no-app-region-drag h-7 bg-indigo-600 text-white dark:bg-indigo-600 dark:text-white text-xs px-2 pt-1 pb-1",
!isDyadProEnabled && "bg-zinc-600 dark:bg-zinc-600", !isDyadProEnabled && "bg-zinc-600 dark:bg-zinc-600",
)} )}
size="sm" size="sm"
> >
{isDyadProEnabled ? "Dyad Pro" : "Dyad Pro (disabled)"} {isDyadProEnabled ? "Pro" : "Pro (off)"}
{userBudget && <AICreditStatus userBudget={userBudget} />} {userBudget && isDyadProEnabled && (
<AICreditStatus userBudget={userBudget} />
)}
</Button> </Button>
); );
} }

View File

@@ -21,6 +21,12 @@ import {
DropdownMenuItem, DropdownMenuItem,
DropdownMenuTrigger, DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"; } from "@/components/ui/dropdown-menu";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { showError, showSuccess } from "@/lib/toast"; import { showError, showSuccess } from "@/lib/toast";
import { useMutation } from "@tanstack/react-query"; import { useMutation } from "@tanstack/react-query";
import { useCheckProblems } from "@/hooks/useCheckProblems"; import { useCheckProblems } from "@/hooks/useCheckProblems";
@@ -28,6 +34,9 @@ import { isPreviewOpenAtom } from "@/atoms/viewAtoms";
export type PreviewMode = "preview" | "code" | "problems" | "configure"; export type PreviewMode = "preview" | "code" | "problems" | "configure";
const BUTTON_CLASS_NAME =
"cursor-pointer relative flex items-center gap-1 px-2 py-1 rounded-md text-[13px] font-medium z-10 hover:bg-[var(--background)]";
// Preview Header component with preview mode toggle // Preview Header component with preview mode toggle
export const PreviewHeader = () => { export const PreviewHeader = () => {
const [previewMode, setPreviewMode] = useAtom(previewModeAtom); const [previewMode, setPreviewMode] = useAtom(previewModeAtom);
@@ -38,9 +47,22 @@ export const PreviewHeader = () => {
const problemsRef = useRef<HTMLButtonElement>(null); const problemsRef = useRef<HTMLButtonElement>(null);
const configureRef = useRef<HTMLButtonElement>(null); const configureRef = useRef<HTMLButtonElement>(null);
const [indicatorStyle, setIndicatorStyle] = useState({ left: 0, width: 0 }); const [indicatorStyle, setIndicatorStyle] = useState({ left: 0, width: 0 });
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
const { problemReport } = useCheckProblems(selectedAppId); const { problemReport } = useCheckProblems(selectedAppId);
const { restartApp, refreshAppIframe } = useRunApp(); const { restartApp, refreshAppIframe } = useRunApp();
const isCompact = windowWidth < 840;
// Track window width
useEffect(() => {
const handleResize = () => {
setWindowWidth(window.innerWidth);
};
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
const selectPanel = (panel: PreviewMode) => { const selectPanel = (panel: PreviewMode) => {
if (previewMode === panel) { if (previewMode === panel) {
setIsPreviewOpen(!isPreviewOpen); setIsPreviewOpen(!isPreviewOpen);
@@ -130,11 +152,47 @@ export const PreviewHeader = () => {
// Small delay to ensure DOM is updated // Small delay to ensure DOM is updated
const timeoutId = setTimeout(updateIndicator, 10); const timeoutId = setTimeout(updateIndicator, 10);
return () => clearTimeout(timeoutId); return () => clearTimeout(timeoutId);
}, [previewMode, displayCount, isPreviewOpen]); }, [previewMode, displayCount, isPreviewOpen, isCompact]);
const renderButton = (
mode: PreviewMode,
ref: React.RefObject<HTMLButtonElement | null>,
icon: React.ReactNode,
text: string,
testId: string,
badge?: React.ReactNode,
) => {
const buttonContent = (
<button
data-testid={testId}
ref={ref}
className={BUTTON_CLASS_NAME}
onClick={() => selectPanel(mode)}
>
{icon}
{!isCompact && <span>{text}</span>}
{badge}
</button>
);
if (isCompact) {
return (
<Tooltip>
<TooltipTrigger asChild>{buttonContent}</TooltipTrigger>
<TooltipContent>
<p>{text}</p>
</TooltipContent>
</Tooltip>
);
}
return buttonContent;
};
return ( return (
<div className="flex items-center justify-between px-4 py-2 mt-1 border-b border-border"> <TooltipProvider>
<div className="relative flex rounded-md p-0.5 gap-2"> <div className="flex items-center justify-between px-1 py-2 mt-1 border-b border-border">
<div className="relative flex rounded-md p-0.5 gap-0.5">
<motion.div <motion.div
className="absolute top-0.5 bottom-0.5 bg-[var(--background-lightest)] shadow rounded-md" className="absolute top-0.5 bottom-0.5 bg-[var(--background-lightest)] shadow rounded-md"
animate={{ animate={{
@@ -148,48 +206,39 @@ export const PreviewHeader = () => {
mass: 0.6, mass: 0.6,
}} }}
/> />
<button {renderButton(
data-testid="preview-mode-button" "preview",
ref={previewRef} previewRef,
className="cursor-pointer relative flex items-center gap-1 px-2 py-1 rounded-md text-sm font-medium z-10 hover:bg-[var(--background)]" <Eye size={14} />,
onClick={() => selectPanel("preview")} "Preview",
> "preview-mode-button",
<Eye size={14} /> )}
<span>Preview</span> {renderButton(
</button> "problems",
<button problemsRef,
data-testid="problems-mode-button" <AlertTriangle size={14} />,
ref={problemsRef} "Problems",
className="cursor-pointer relative flex items-center gap-1 px-2 py-1 rounded-md text-sm font-medium z-10 hover:bg-[var(--background)]" "problems-mode-button",
onClick={() => selectPanel("problems")} displayCount && (
>
<AlertTriangle size={14} />
<span>Problems</span>
{displayCount && (
<span className="ml-0.5 px-1 py-0.5 text-xs font-medium bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-300 rounded-full min-w-[16px] text-center"> <span className="ml-0.5 px-1 py-0.5 text-xs font-medium bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-300 rounded-full min-w-[16px] text-center">
{displayCount} {displayCount}
</span> </span>
),
)}
{renderButton(
"code",
codeRef,
<Code size={14} />,
"Code",
"code-mode-button",
)}
{renderButton(
"configure",
configureRef,
<Wrench size={14} />,
"Configure",
"configure-mode-button",
)} )}
</button>
<button
data-testid="code-mode-button"
ref={codeRef}
className="cursor-pointer relative flex items-center gap-1 px-2 py-1 rounded-md text-sm font-medium z-10 hover:bg-[var(--background)]"
onClick={() => selectPanel("code")}
>
<Code size={14} />
<span>Code</span>
</button>
<button
data-testid="configure-mode-button"
ref={configureRef}
className="cursor-pointer relative flex items-center gap-1 px-2 py-1 rounded-md text-sm font-medium z-10 hover:bg-[var(--background)]"
onClick={() => selectPanel("configure")}
>
<Wrench size={14} />
<span>Configure</span>
</button>
</div> </div>
<div className="flex items-center"> <div className="flex items-center">
<DropdownMenu> <DropdownMenu>
@@ -225,5 +274,6 @@ export const PreviewHeader = () => {
</DropdownMenu> </DropdownMenu>
</div> </div>
</div> </div>
</TooltipProvider>
); );
}; };