🚸 feat: redesign AI toolbar with two-zone layout and HoverCard shortcuts popover

- Split composer into AI zone (primary accent) and data actions zone (neutral)
- Move Attach/Generate to labeled footer bar below textarea (left/right aligned)
- Add info icon with HoverCard (hover preview) + Popover (pinned click) showing identical keyboard shortcuts content using shadcn HoverCard to fix theme inconsistency vs Tooltip
- Expose imperative triggerRef on ImagePicker for keyboard shortcut access
- Wire TooltipProvider in root layout; install shadcn kbd and hover-card
- Unauthenticated state shows locked CTA with real sign-in button weight
- Add behavioral contract tests for footer bar, info trigger, and zone layout
This commit is contained in:
2026-04-08 13:08:36 -04:00
parent 650d1d5f95
commit 722c0f0f7d
8 changed files with 881 additions and 151 deletions

View File

@@ -3,7 +3,7 @@
import type { VariantProps } from "class-variance-authority";
import { ImageIcon } from "lucide-react";
import type React from "react";
import { useRef } from "react";
import { useImperativeHandle, useRef } from "react";
import { Button, type buttonVariants } from "@/components/ui/button";
interface ImagePickerProps extends VariantProps<typeof buttonVariants> {
@@ -11,6 +11,8 @@ interface ImagePickerProps extends VariantProps<typeof buttonVariants> {
className?: string;
children?: React.ReactNode;
disabled?: boolean;
/** Expose an imperative trigger so parents can open the file dialog via ref */
triggerRef?: React.Ref<{ open: () => void }>;
}
export function ImagePicker({
@@ -20,9 +22,17 @@ export function ImagePicker({
variant = "ghost",
size = "icon",
disabled = false,
triggerRef,
}: ImagePickerProps) {
const fileInputRef = useRef<HTMLInputElement>(null);
// Expose `.open()` to parent through triggerRef
useImperativeHandle(triggerRef, () => ({
open() {
fileInputRef.current?.click();
},
}));
const handleButtonClick = () => {
fileInputRef.current?.click();
};