fix(webui): improve mobile responsiveness
This commit is contained in:
@@ -1544,10 +1544,10 @@ export function ThreadComposer({
|
||||
"w-full resize-none bg-transparent",
|
||||
isHero
|
||||
? cn(
|
||||
"min-h-[78px] px-5 text-[15px] leading-6",
|
||||
"min-h-[78px] px-4 text-[15px] leading-6 sm:px-5",
|
||||
relaxedHeroInput ? "pb-2 pt-[27px]" : "pb-1.5 pt-4",
|
||||
)
|
||||
: "min-h-[50px] px-4 pb-1.5 pt-3 text-[13.5px] leading-5",
|
||||
: "min-h-[50px] px-3.5 pb-1.5 pt-3 text-[13.5px] leading-5 sm:px-4",
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -1699,11 +1699,13 @@ export function ThreadComposer({
|
||||
) : null}
|
||||
<div
|
||||
className={cn(
|
||||
"flex items-center justify-between",
|
||||
isHero ? cn("gap-1.5 px-4", showProjectPicker ? "pb-1.5" : "pb-3.5") : "gap-2 px-3 pb-2",
|
||||
"flex flex-wrap items-center justify-between gap-y-2",
|
||||
isHero
|
||||
? cn("gap-x-1.5 px-3 sm:px-4", showProjectPicker ? "pb-1.5" : "pb-3.5")
|
||||
: "gap-x-2 px-2.5 pb-2 sm:px-3",
|
||||
)}
|
||||
>
|
||||
<div className={cn("flex min-w-0 flex-1 items-center", isHero ? "gap-1.5" : "gap-2")}>
|
||||
<div className={cn("flex min-w-0 flex-1 basis-[8rem] items-center", isHero ? "gap-1.5" : "gap-2")}>
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
type="file"
|
||||
@@ -1746,7 +1748,7 @@ export function ThreadComposer({
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
<div className={cn("flex shrink-0 items-center", isHero ? "gap-1.5" : "gap-2")}>
|
||||
<div className={cn("ml-auto flex min-w-0 shrink-0 items-center", isHero ? "gap-1.5" : "gap-2")}>
|
||||
{modelLabel && !voiceRecorder.isRecording ? (
|
||||
<ComposerModelBadge
|
||||
label={modelLabel}
|
||||
@@ -1768,6 +1770,7 @@ export function ThreadComposer({
|
||||
disabled={voiceRecorder.buttonDisabled}
|
||||
aria-label={voiceButtonLabel}
|
||||
aria-keyshortcuts={VOICE_SHORTCUT_ARIA}
|
||||
title={voiceButtonTooltip}
|
||||
onPointerDown={voiceRecorder.beginPress}
|
||||
onPointerUp={voiceRecorder.endPress}
|
||||
onPointerCancel={voiceRecorder.endPress}
|
||||
@@ -2071,7 +2074,9 @@ function ComposerModelBadge({
|
||||
"shadow-[0_2px_8px_rgba(15,23,42,0.045)]",
|
||||
interactive && "cursor-pointer hover:bg-accent/55 hover:text-foreground",
|
||||
needsSetup && "border-amber-500/35 bg-amber-50/70 text-amber-900 dark:bg-amber-500/10 dark:text-amber-200",
|
||||
isHero ? "h-8 max-w-[12.5rem] gap-1.5 px-2 text-[11.5px]" : "h-9 max-w-[12rem] gap-2 px-2.5 text-[12px]",
|
||||
isHero
|
||||
? "h-8 max-w-[min(12.5rem,44vw)] gap-1.5 px-2 text-[11.5px]"
|
||||
: "h-9 max-w-[min(12rem,44vw)] gap-2 px-2.5 text-[12px]",
|
||||
)}
|
||||
>
|
||||
<span
|
||||
@@ -2252,7 +2257,7 @@ function CliAppMentionPalette({
|
||||
onChoose(candidate);
|
||||
}}
|
||||
className={cn(
|
||||
"flex h-10 w-full items-center gap-2.5 rounded-[13px] px-2.5 text-left transition-colors",
|
||||
"flex min-h-10 w-full items-center gap-2.5 rounded-[13px] px-2.5 py-1.5 text-left transition-colors",
|
||||
selected
|
||||
? "bg-foreground/[0.055] text-foreground"
|
||||
: "text-foreground/90 hover:bg-foreground/[0.04]",
|
||||
@@ -2260,7 +2265,7 @@ function CliAppMentionPalette({
|
||||
>
|
||||
<MentionCandidateLogo candidate={candidate} selected={selected} />
|
||||
<span className="flex min-w-0 flex-1 items-baseline gap-2">
|
||||
<span className="shrink-0 text-[15px] font-medium tracking-normal text-foreground">
|
||||
<span className="min-w-0 truncate text-[15px] font-medium tracking-normal text-foreground">
|
||||
{displayName}
|
||||
</span>
|
||||
<span className="truncate text-[15px] font-normal tracking-normal text-muted-foreground/72">
|
||||
@@ -2396,7 +2401,7 @@ function SlashCommandPalette({
|
||||
>
|
||||
<Icon className="h-4 w-4" />
|
||||
</span>
|
||||
<span className="flex min-w-0 flex-1 items-baseline gap-2">
|
||||
<span className="flex min-w-0 flex-1 flex-col gap-0.5 sm:flex-row sm:items-baseline sm:gap-2">
|
||||
<span className="min-w-0 truncate text-[13.5px] font-semibold tracking-normal text-foreground">
|
||||
{title}
|
||||
</span>
|
||||
@@ -2404,7 +2409,7 @@ function SlashCommandPalette({
|
||||
{command.detail || description}
|
||||
</span>
|
||||
</span>
|
||||
<span className="ml-2 flex shrink-0 items-center gap-1.5">
|
||||
<span className="ml-2 flex max-w-[42%] shrink-0 items-center gap-1.5 sm:max-w-none">
|
||||
{command.badge || command.recent ? (
|
||||
<span className="hidden rounded-full bg-foreground/[0.055] px-2 py-1 text-[11px] font-medium text-muted-foreground sm:inline-flex">
|
||||
{command.badge ?? t("thread.composer.slash.badges.recent")}
|
||||
@@ -2486,7 +2491,7 @@ function AttachmentChip({
|
||||
) : null}
|
||||
</div>
|
||||
<div className="flex min-w-0 flex-col text-[11.5px] leading-4">
|
||||
<span className="truncate max-w-[14rem] font-medium" title={image.file.name}>
|
||||
<span className="max-w-[min(14rem,calc(100vw-8rem))] truncate font-medium" title={image.file.name}>
|
||||
{image.file.name}
|
||||
</span>
|
||||
<span className="truncate text-muted-foreground">
|
||||
|
||||
@@ -725,7 +725,7 @@ export function ThreadShell({
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex w-full flex-col items-center text-center animate-in fade-in-0 slide-in-from-bottom-2 duration-500">
|
||||
<h1 className="text-balance text-[40px] font-normal leading-tight tracking-[-0.045em] text-foreground sm:text-[48px]">
|
||||
<h1 className="max-w-[30rem] text-balance text-[34px] font-normal leading-[1.08] tracking-normal text-foreground sm:text-[48px] sm:leading-tight">
|
||||
{t(heroGreetingKey)}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
@@ -335,7 +335,7 @@ export const ThreadViewport = forwardRef<ThreadViewportHandle, ThreadViewportPro
|
||||
>
|
||||
{hasMessages ? (
|
||||
<div ref={contentRef} className="mx-auto flex min-h-full w-full max-w-[64rem] flex-col">
|
||||
<div className="flex-1 px-4 pb-20 pt-4">
|
||||
<div className="flex-1 px-3 pb-[calc(5rem+env(safe-area-inset-bottom))] pt-4 sm:px-4">
|
||||
<div className="mx-auto w-full max-w-[49.5rem]">
|
||||
<ThreadMessages
|
||||
messages={visibleMessages}
|
||||
@@ -355,16 +355,16 @@ export const ThreadViewport = forwardRef<ThreadViewportHandle, ThreadViewportPro
|
||||
data-testid="thread-composer-dock"
|
||||
className="sticky bottom-0 z-10 mt-auto bg-background"
|
||||
>
|
||||
<div className="px-4 pb-3">
|
||||
<div className="px-3 pb-[calc(0.75rem+env(safe-area-inset-bottom))] sm:px-4">
|
||||
{composer}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div ref={contentRef} className="mx-auto flex min-h-full w-full max-w-[72rem] flex-col px-4">
|
||||
<div className="flex w-full flex-1 items-center justify-center py-10 sm:py-12">
|
||||
<div className="relative w-full max-w-[58rem]">
|
||||
<div className="absolute inset-x-0 bottom-[calc(100%+1.5rem)] flex justify-center">
|
||||
<div ref={contentRef} className="mx-auto flex min-h-full w-full max-w-[72rem] flex-col px-3 sm:px-4">
|
||||
<div className="flex w-full flex-1 items-center justify-center py-6 sm:py-12">
|
||||
<div className="relative flex w-full max-w-[58rem] flex-col items-center gap-5 sm:block">
|
||||
<div className="flex justify-center sm:absolute sm:inset-x-0 sm:bottom-[calc(100%+1.5rem)]">
|
||||
{emptyState}
|
||||
</div>
|
||||
<div className="w-full">{composer}</div>
|
||||
|
||||
@@ -106,7 +106,7 @@ export function WorkspaceProjectPicker({
|
||||
|
||||
if (nativeProjectPicker) {
|
||||
return (
|
||||
<div className="flex items-center rounded-b-[28px] border-t border-border/25 bg-muted/60 px-4 py-1.5 dark:bg-white/[0.055]">
|
||||
<div className="flex min-w-0 items-center rounded-b-[28px] border-t border-border/25 bg-muted/60 px-3 py-1.5 dark:bg-white/[0.055] sm:px-4">
|
||||
<button
|
||||
type="button"
|
||||
disabled={disabled || pickingFolder}
|
||||
@@ -114,7 +114,7 @@ export function WorkspaceProjectPicker({
|
||||
title={currentProjectScope?.project_path}
|
||||
onClick={() => void pickNativeFolder()}
|
||||
className={cn(
|
||||
"inline-flex h-7 max-w-[18rem] items-center gap-2 rounded-full px-2.5",
|
||||
"inline-flex h-7 max-w-full items-center gap-2 rounded-full px-2.5 sm:max-w-[18rem]",
|
||||
"text-[12px] font-medium text-muted-foreground/90 transition-colors",
|
||||
"hover:bg-background/70 hover:text-foreground disabled:pointer-events-none disabled:opacity-55",
|
||||
currentProjectScope && "text-foreground/82",
|
||||
@@ -124,7 +124,7 @@ export function WorkspaceProjectPicker({
|
||||
<span className="truncate">{projectLabel}</span>
|
||||
</button>
|
||||
{pathError || error ? (
|
||||
<span role="alert" className="ml-2 truncate text-[11.5px] font-medium text-destructive">
|
||||
<span role="alert" className="ml-2 min-w-0 truncate text-[11.5px] font-medium text-destructive">
|
||||
{pathError ?? error}
|
||||
</span>
|
||||
) : null}
|
||||
@@ -133,7 +133,7 @@ export function WorkspaceProjectPicker({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center rounded-b-[28px] border-t border-border/25 bg-muted/60 px-4 py-1.5 dark:bg-white/[0.055]">
|
||||
<div className="flex min-w-0 items-center rounded-b-[28px] border-t border-border/25 bg-muted/60 px-3 py-1.5 dark:bg-white/[0.055] sm:px-4">
|
||||
<DropdownMenu open={open} onOpenChange={setOpen}>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button
|
||||
@@ -141,7 +141,7 @@ export function WorkspaceProjectPicker({
|
||||
disabled={disabled}
|
||||
aria-label={t("thread.composer.workspace.projectAria")}
|
||||
className={cn(
|
||||
"inline-flex h-7 max-w-[18rem] items-center gap-2 rounded-full px-2.5",
|
||||
"inline-flex h-7 max-w-full items-center gap-2 rounded-full px-2.5 sm:max-w-[18rem]",
|
||||
"text-[12px] font-medium text-muted-foreground/90 transition-colors",
|
||||
"hover:bg-background/70 hover:text-foreground disabled:pointer-events-none disabled:opacity-55",
|
||||
currentProjectScope && "text-foreground/82",
|
||||
@@ -254,7 +254,7 @@ export function WorkspaceAccessMenu({
|
||||
variant="ghost"
|
||||
aria-label={t("thread.composer.workspace.accessAria")}
|
||||
className={cn(
|
||||
"max-w-[12.5rem] rounded-[10px] border border-transparent font-semibold shadow-none",
|
||||
"max-w-[min(12.5rem,42vw)] rounded-[10px] border border-transparent font-semibold shadow-none",
|
||||
isHero ? "h-8 px-2.5 text-[12px]" : "h-9 px-3 text-[12.5px]",
|
||||
isFull
|
||||
? "bg-transparent text-orange-600 hover:bg-orange-500/8 dark:text-orange-300 dark:hover:bg-orange-400/10"
|
||||
|
||||
Reference in New Issue
Block a user