fix(web): keep import controls inside their scroller, so the document stops scrolling (#116)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
b40262d43c
commit
f63037866e
6 files changed
+139
-27
No files matched your search
@@ -27,6 +27,7 @@ import { useProject } from "../../state/project";
|
||||
import { Tabs } from "../../components/ui/tabs";
|
||||
import { Button } from "../../components/ui/button";
|
||||
import { toastError, toastInfo, toastSuccess } from "../../components/ui/toast";
|
||||
import { HiddenFileInput } from "../../components/ui/hidden-file-input";
|
||||
import { Input, Textarea } from "../../components/ui/input";
|
||||
import { OptionMenu, type OptionMenuChoice } from "../../components/ui/option-menu";
|
||||
import { Switch } from "../../components/ui/switch";
|
||||
@@ -156,7 +157,9 @@ export function AgentSettingsPage() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="no-scrollbar h-full overflow-y-auto p-4 md:p-6">
|
||||
/* relative: a scroller is its own containing block (see the invariant in styles.css) —
|
||||
this page's snapshot-import control used to grow the document from below the fold. */
|
||||
<div className="no-scrollbar relative h-full overflow-y-auto p-4 md:p-6">
|
||||
<div className="mx-auto max-w-3xl">
|
||||
<Button
|
||||
variant="ghost"
|
||||
@@ -351,14 +354,7 @@ function OverviewTab({
|
||||
<label
|
||||
className={`${TRANSFER_BUTTON_CLASS} ${importing ? "pointer-events-none opacity-60" : ""}`}
|
||||
>
|
||||
{/* sr-only rather than hidden: keeps it keyboard-Tab-focusable (same as the workspace-browser upload). */}
|
||||
<input
|
||||
type="file"
|
||||
accept=".tar.gz,.tgz"
|
||||
className="sr-only"
|
||||
disabled={importing}
|
||||
onChange={onPickFile}
|
||||
/>
|
||||
<HiddenFileInput accept=".tar.gz,.tgz" disabled={importing} onChange={onPickFile} />
|
||||
{importing ? S.agent.importing : S.agent.importSnapshot}
|
||||
</label>
|
||||
)}
|
||||
|
||||
@@ -27,6 +27,7 @@ import { Button } from "../../components/ui/button";
|
||||
import { ConfirmModal } from "../../components/ui/confirm-modal";
|
||||
import { toastError, toastSuccess } from "../../components/ui/toast";
|
||||
import { Dropdown } from "../../components/ui/dropdown";
|
||||
import { HiddenFileInput } from "../../components/ui/hidden-file-input";
|
||||
import { SkeletonList } from "../../components/ui/skeleton";
|
||||
import { CodeBlock } from "./code-block";
|
||||
|
||||
@@ -745,14 +746,7 @@ export function WorkspaceBrowser({
|
||||
</Button>
|
||||
{/* Matches the same visual style and font size (sm = text-xs) as the adjacent ghost Buttons (Details/Refresh): no border, light background on hover. */}
|
||||
<label className="inline-flex cursor-pointer items-center rounded-md border border-transparent bg-transparent px-2.5 py-1 text-xs font-medium text-gray-600 transition-colors duration-150 focus-within:ring-2 focus-within:ring-gray-400/30 hover:bg-gray-100 hover:text-gray-900 dark:text-gray-300 dark:hover:bg-gray-800 dark:hover:text-gray-100">
|
||||
{/* sr-only rather than hidden: keyboard users can still Tab-focus it (display:none would remove it from the focus order). */}
|
||||
<input
|
||||
type="file"
|
||||
multiple
|
||||
className="sr-only"
|
||||
onChange={onUpload}
|
||||
disabled={uploading}
|
||||
/>
|
||||
<HiddenFileInput multiple onChange={onUpload} disabled={uploading} />
|
||||
{uploading ? S.common.saving : S.files.upload}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@@ -17,6 +17,7 @@ import { formatBytes } from "../../lib/format";
|
||||
import { agentDisplayName, useProject } from "../../state/project";
|
||||
import { AgentAvatar } from "../../components/ui/agent-avatar";
|
||||
import { Chevron } from "../../components/ui/chevron";
|
||||
import { HiddenFileInput } from "../../components/ui/hidden-file-input";
|
||||
import { DownloadIcon, UploadIcon } from "../../components/ui/icons";
|
||||
import { toastError } from "../../components/ui/toast";
|
||||
import { Truncated } from "../../components/ui/truncated";
|
||||
@@ -197,14 +198,7 @@ function AgentNode({
|
||||
importing ? "pointer-events-none opacity-60" : ""
|
||||
}`}
|
||||
>
|
||||
{/* sr-only rather than hidden: keeps it keyboard-Tab-focusable (same as the snapshot import). */}
|
||||
<input
|
||||
type="file"
|
||||
accept=".jsonl"
|
||||
className="sr-only"
|
||||
disabled={importing}
|
||||
onChange={onPickFile}
|
||||
/>
|
||||
<HiddenFileInput accept=".jsonl" disabled={importing} onChange={onPickFile} />
|
||||
<UploadIcon size={13} />
|
||||
<span className="sr-only">{importing ? S.traces.importing : S.traces.importTrace}</span>
|
||||
</label>
|
||||
@@ -297,8 +291,12 @@ export function TracesPage() {
|
||||
|
||||
return (
|
||||
<div className="flex h-full flex-col md:flex-row">
|
||||
{/* Directory tree: Agent → Session title (≥md left column; <md top collapsible area) */}
|
||||
<aside className="max-h-52 shrink-0 overflow-y-auto border-b border-gray-200 bg-gray-50 px-1 py-2 md:max-h-none md:w-72 md:border-b-0 md:border-r dark:border-gray-800 dark:bg-gray-900">
|
||||
{/* Directory tree: Agent → Session title (≥md left column; <md top collapsible area).
|
||||
relative: a scroller is its own containing block — the invariant and the failure it
|
||||
prevents are documented in styles.css; this is where it first bit (an Agent node past
|
||||
the fold put its import control's absolutely positioned box at a document-level
|
||||
offset, growing the document). */}
|
||||
<aside className="relative max-h-52 shrink-0 overflow-y-auto border-b border-gray-200 bg-gray-50 px-1 py-2 md:max-h-none md:w-72 md:border-b-0 md:border-r dark:border-gray-800 dark:bg-gray-900">
|
||||
<p className="px-3 pb-1 text-xs font-bold uppercase tracking-wide text-gray-500">
|
||||
{S.traces.title}
|
||||
</p>
|
||||
|
||||
Reference in new issue
Block a user