mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-09-30 08:03:15 +00:00
fix: tidy agents home + mobile logo + PWA dev/icon issues (#1419)
* fix: tidy agents home, mobile logo, and PWA dev/icon issues - Remove recent-runs cards from the new agent page - Scale the ASCII logo to fit narrow viewports instead of overflowing - Serve manifest in dev and skip SW registration in dev to clear console errors - Use a flat, opaque apple-touch-icon so iOS stops adding a black border - Ignore generated ui/dev-dist * feat: add send button and prevent iOS focus-zoom on chat input - Add a circular send button (accent, spinner while sending) to the prompt bar - Bump textarea to 16px on mobile so iOS doesn't zoom the viewport on focus * fix: polish prompt bar and center logo - Center the ASCII logo at all widths - Prevent iOS focus-zoom via viewport maximum-scale instead of bumping the input to 16px, so mobile text stays the intended size - Give the model picker a chip/chevron treatment to anchor it next to the send button * fix: simplify model picker to plain text + chevron * fix: tighten prompt bar padding and shrink send button --------- Co-authored-by: open-swe[bot] <215916821+open-swe[bot]@users.noreply.github.com>
This commit is contained in:
parent
a511add856
commit
6f330f777d
8 changed files with 44 additions and 43 deletions
1
ui/.gitignore
vendored
1
ui/.gitignore
vendored
|
|
@ -10,5 +10,6 @@ count.txt
|
|||
.wrangler
|
||||
.output
|
||||
.vinxi
|
||||
dev-dist
|
||||
__unconfig*
|
||||
todos.json
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 14 KiB |
|
|
@ -4,8 +4,11 @@ import { hydrateRoot } from "react-dom/client"
|
|||
import { registerSW } from "virtual:pwa-register"
|
||||
|
||||
// prompt mode: a new SW installs in the background and takes over on the next
|
||||
// load, so deploys never reload a tab mid-agent-run.
|
||||
registerSW()
|
||||
// load, so deploys never reload a tab mid-agent-run. Skip in dev — the SW
|
||||
// precaches production-only build artifacts that 404 against the dev server.
|
||||
if (import.meta.env.PROD) {
|
||||
registerSW()
|
||||
}
|
||||
|
||||
hydrateRoot(
|
||||
document,
|
||||
|
|
|
|||
|
|
@ -1,19 +1,15 @@
|
|||
import { Link } from "@tanstack/react-router"
|
||||
import { useState } from "react"
|
||||
|
||||
import type { ModelSelection } from "@/lib/agents/useModelOptions"
|
||||
import { AgentPromptBar } from "@/components/agents/AgentPromptBar"
|
||||
import { AgentRunCard } from "@/components/agents/AgentRunCard"
|
||||
import { SlackConnectDialog } from "@/components/agents/SlackConnectDialog"
|
||||
import { Logo } from "@/components/agents/ported/Logo"
|
||||
import { useAgentThreads, useCreateAgentThread } from "@/lib/agents/queries"
|
||||
import { useCreateAgentThread } from "@/lib/agents/queries"
|
||||
import { useModelOptions } from "@/lib/agents/useModelOptions"
|
||||
import { useProfile, useRepos } from "@/lib/profile"
|
||||
|
||||
export function AgentsHome() {
|
||||
const threadsQuery = useAgentThreads()
|
||||
const createThread = useCreateAgentThread()
|
||||
const recentRuns = (threadsQuery.data ?? []).slice(0, 5)
|
||||
const { models, defaultSelection } = useModelOptions()
|
||||
const [selection, setSelection] = useState<ModelSelection | null>(null)
|
||||
const activeSelection = selection ?? defaultSelection
|
||||
|
|
@ -53,35 +49,7 @@ export function AgentsHome() {
|
|||
onRepoChange={setRepoOverride}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mx-auto mt-6 w-full max-w-[640px] space-y-2">
|
||||
{threadsQuery.isLoading ? (
|
||||
<p className="text-center text-sm text-[var(--ui-text-dim)]">
|
||||
Loading agents…
|
||||
</p>
|
||||
) : recentRuns.length === 0 ? (
|
||||
<AgentsHomeEmptyState />
|
||||
) : (
|
||||
recentRuns.map((thread) => (
|
||||
<AgentRunCard key={thread.id} thread={thread} />
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function AgentsHomeEmptyState() {
|
||||
return (
|
||||
<div className="flex flex-col items-center gap-3 py-4 text-center">
|
||||
<p className="text-sm text-[var(--ui-text-muted)]">No agents yet.</p>
|
||||
<Link
|
||||
to="/agents"
|
||||
className="text-sm font-medium text-[var(--ui-accent)] hover:underline"
|
||||
>
|
||||
Start your first agent
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { ArrowUp, ChevronDown, LoaderCircle } from "lucide-react"
|
||||
import {
|
||||
memo,
|
||||
useCallback,
|
||||
|
|
@ -121,7 +122,7 @@ export const CloudPromptBar = memo(function CloudPromptBarComponent({
|
|||
)}
|
||||
<div
|
||||
className={cn(
|
||||
"relative flex min-h-[106px] flex-col rounded-2xl border border-[var(--ui-border)] bg-[var(--ui-surface)] px-4 py-3.5 shadow-sm",
|
||||
"relative flex min-h-[106px] flex-col rounded-2xl border border-[var(--ui-border)] bg-[var(--ui-surface)] px-3 py-2.5 shadow-sm",
|
||||
compact && "min-h-[88px]"
|
||||
)}
|
||||
>
|
||||
|
|
@ -134,7 +135,7 @@ export const CloudPromptBar = memo(function CloudPromptBarComponent({
|
|||
placeholder={busy ? "Send a message to queue next..." : placeholder}
|
||||
disabled={disabled}
|
||||
className={cn(
|
||||
"w-full min-w-0 resize-none overflow-hidden bg-transparent leading-[1.45] text-[color:var(--ui-text)] outline-none placeholder:text-[color:var(--ui-text-dim)]",
|
||||
"w-full min-w-0 resize-none overflow-hidden bg-transparent text-[13px] leading-[1.45] text-[color:var(--ui-text)] outline-none placeholder:text-[color:var(--ui-text-dim)]",
|
||||
compact ? "min-h-[36px]" : "min-h-[52px]"
|
||||
)}
|
||||
style={{ maxHeight: PROMPT_TEXTAREA_MAX_HEIGHT }}
|
||||
|
|
@ -146,9 +147,12 @@ export const CloudPromptBar = memo(function CloudPromptBarComponent({
|
|||
type="button"
|
||||
disabled={pickerDisabled}
|
||||
onClick={() => setModelDropdownOpen((open) => !open)}
|
||||
className="max-w-[220px] cursor-pointer truncate text-[color:var(--ui-text-muted)] transition-opacity hover:opacity-80 disabled:cursor-default disabled:opacity-60"
|
||||
className="flex max-w-[220px] cursor-pointer items-center gap-0.5 text-[13px] text-[color:var(--ui-text-muted)] transition-opacity hover:opacity-80 disabled:cursor-default disabled:opacity-60"
|
||||
>
|
||||
{selectionLabel}
|
||||
<span className="truncate">{selectionLabel}</span>
|
||||
{!pickerDisabled && (
|
||||
<ChevronDown className="size-3.5 shrink-0 opacity-60" />
|
||||
)}
|
||||
</button>
|
||||
{modelDropdownOpen && combos.length > 0 && (
|
||||
<div className="absolute bottom-full left-0 z-50 mb-1 max-h-72 overflow-hidden overflow-y-auto rounded border border-[var(--ui-border)] bg-[var(--ui-surface)] shadow-lg">
|
||||
|
|
@ -184,6 +188,20 @@ export const CloudPromptBar = memo(function CloudPromptBarComponent({
|
|||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleSubmit}
|
||||
disabled={!value.trim() || disabled}
|
||||
aria-label="Send message"
|
||||
className="ml-auto flex size-7 shrink-0 items-center justify-center rounded-full bg-[var(--ui-accent)] text-white transition-opacity hover:opacity-90 disabled:cursor-default disabled:opacity-40"
|
||||
>
|
||||
{disabled ? (
|
||||
<LoaderCircle className="size-3.5 animate-spin" />
|
||||
) : (
|
||||
<ArrowUp className="size-3.5" strokeWidth={2.5} />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -12,8 +12,13 @@ export function Logo() {
|
|||
].join("\n");
|
||||
|
||||
return (
|
||||
<pre className="m-0 max-w-full overflow-x-auto font-mono text-[7px] leading-none text-[#87CEEB]">
|
||||
{ascii}
|
||||
</pre>
|
||||
<div className="w-full" style={{ containerType: "inline-size" }}>
|
||||
<pre
|
||||
className="m-0 w-full overflow-hidden text-center font-mono leading-none text-[#87CEEB]"
|
||||
style={{ fontSize: "min(7px, 1.9cqw)" }}
|
||||
>
|
||||
{ascii}
|
||||
</pre>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,10 @@ export const Route = createRootRoute({
|
|||
head: () => ({
|
||||
meta: [
|
||||
{ charSet: "utf-8" },
|
||||
{ name: "viewport", content: "width=device-width, initial-scale=1" },
|
||||
{
|
||||
name: "viewport",
|
||||
content: "width=device-width, initial-scale=1, maximum-scale=1",
|
||||
},
|
||||
{ name: "theme-color", content: "#000000" },
|
||||
{ title: "open-swe" },
|
||||
],
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@ const config = defineConfig({
|
|||
injectRegister: false,
|
||||
registerType: "prompt",
|
||||
outDir: ".output/public",
|
||||
devOptions: {
|
||||
enabled: true,
|
||||
},
|
||||
integration: {
|
||||
closeBundleOrder: "pre",
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue