Skip to content

Commit 7bb7b75

Browse files
brunobergherroomote[bot]ellipsis-dev[bot]roomote
authored
ux: Home screen visuals (#9057)
Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com> Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> Co-authored-by: Roo Code <[email protected]>
1 parent 63b4a78 commit 7bb7b75

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+306
-460
lines changed

webview-ui/src/components/chat/ChatTextArea.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -979,7 +979,7 @@ export const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
979979
"flex-col-reverse",
980980
"min-h-0",
981981
"overflow-hidden",
982-
"rounded",
982+
"rounded-lg",
983983
)}>
984984
<div
985985
ref={highlightLayerRef}
@@ -1005,7 +1005,7 @@ export const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
10051005
isEditMode ? "pr-20" : "pr-9",
10061006
"z-10",
10071007
"forced-color-adjust-none",
1008-
"rounded",
1008+
"rounded-lg",
10091009
)}
10101010
style={{
10111011
color: "transparent",

webview-ui/src/components/chat/ChatView.tsx

Lines changed: 24 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ import { CloudUpsellDialog } from "@src/components/cloud/CloudUpsellDialog"
4444

4545
import TelemetryBanner from "../common/TelemetryBanner"
4646
import VersionIndicator from "../common/VersionIndicator"
47-
import { useTaskSearch } from "../history/useTaskSearch"
4847
import HistoryPreview from "../history/HistoryPreview"
4948
import Announcement from "./Announcement"
5049
import BrowserSessionRow from "./BrowserSessionRow"
@@ -118,7 +117,6 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
118117
customModes,
119118
telemetrySetting,
120119
hasSystemPromptOverride,
121-
historyPreviewCollapsed, // Added historyPreviewCollapsed
122120
soundEnabled,
123121
soundVolume,
124122
cloudIsAuthenticated,
@@ -131,20 +129,6 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
131129
messagesRef.current = messages
132130
}, [messages])
133131

134-
const { tasks } = useTaskSearch()
135-
136-
// Initialize expanded state based on the persisted setting (default to expanded if undefined)
137-
const [isExpanded, setIsExpanded] = useState(
138-
historyPreviewCollapsed === undefined ? true : !historyPreviewCollapsed,
139-
)
140-
141-
const toggleExpanded = useCallback(() => {
142-
const newState = !isExpanded
143-
setIsExpanded(newState)
144-
// Send message to extension to persist the new collapsed state
145-
vscode.postMessage({ type: "setHistoryPreviewCollapsed", bool: !newState })
146-
}, [isExpanded])
147-
148132
// Leaving this less safe version here since if the first message is not a
149133
// task, then the extension is in a bad state and needs to be debugged (see
150134
// Cline.abort).
@@ -1810,53 +1794,35 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
18101794
)}
18111795
</>
18121796
) : (
1813-
<div className="flex-1 min-h-0 overflow-y-auto flex flex-col gap-4 relative">
1814-
{/* Moved Task Bar Header Here */}
1815-
{tasks.length !== 0 && (
1816-
<div className="flex text-vscode-descriptionForeground w-full mx-auto px-5 pt-3">
1817-
<div className="flex items-center gap-1 cursor-pointer" onClick={toggleExpanded}>
1818-
{tasks.length < 10 && (
1819-
<span className={`font-medium text-xs `}>{t("history:recentTasks")}</span>
1820-
)}
1821-
<span
1822-
className={`codicon ${isExpanded ? "codicon-eye" : "codicon-eye-closed"} scale-90`}
1823-
/>
1824-
</div>
1825-
</div>
1826-
)}
1827-
<div
1828-
className={` w-full flex flex-col gap-4 m-auto ${isExpanded && tasks.length > 0 ? "mt-0" : ""} px-3.5 min-[370px]:px-10 pt-5 transition-all duration-300`}>
1829-
{/* Version indicator in top-right corner - only on welcome screen */}
1797+
<div className="flex flex-col h-full justify-center p-6 min-h-0 overflow-y-auto gap-4 relative">
1798+
<div className="flex flex-col items-start gap-2 justify-center h-full min-[400px]:px-6">
18301799
<VersionIndicator
18311800
onClick={() => setShowAnnouncementModal(true)}
18321801
className="absolute top-2 right-3 z-10"
18331802
/>
1834-
1835-
<RooHero />
1836-
1837-
<div className="mb-2.5">
1838-
{cloudIsAuthenticated || taskHistory.length < 4 ? (
1839-
<RooTips />
1840-
) : (
1841-
<>
1842-
<DismissibleUpsell
1843-
upsellId="taskList"
1844-
icon={<Cloud className="size-4 mt-0.5 shrink-0" />}
1845-
onClick={() => openUpsell()}
1846-
dismissOnClick={false}
1847-
className="bg-vscode-editor-background p-4 !text-base">
1848-
<Trans
1849-
i18nKey="cloud:upsell.taskList"
1850-
components={{
1851-
learnMoreLink: <VSCodeLink href="#" />,
1852-
}}
1853-
/>
1854-
</DismissibleUpsell>
1855-
</>
1856-
)}
1803+
<div className="flex flex-col gap-4 w-full">
1804+
<RooHero />
1805+
{/* Show RooTips when authenticated or when user is new */}
1806+
{taskHistory.length < 6 && <RooTips />}
1807+
{/* Everyone should see their task history if any */}
1808+
{taskHistory.length > 0 && <HistoryPreview />}
18571809
</div>
1858-
{/* Show the task history preview if expanded and tasks exist */}
1859-
{taskHistory.length > 0 && isExpanded && <HistoryPreview />}
1810+
{/* Logged out users should see a one-time upsell, but not for brand new users */}
1811+
{!cloudIsAuthenticated && taskHistory.length >= 6 && (
1812+
<DismissibleUpsell
1813+
upsellId="taskList2"
1814+
icon={<Cloud className="size-5 mt-0.5 shrink-0" />}
1815+
onClick={() => openUpsell()}
1816+
dismissOnClick={false}
1817+
className="!bg-vscode-editor-background mt-6 border-border rounded-xl pl-4 pr-3 py-3 !text-base">
1818+
<Trans
1819+
i18nKey="cloud:upsell.taskList"
1820+
components={{
1821+
learnMoreLink: <VSCodeLink href="#" />,
1822+
}}
1823+
/>
1824+
</DismissibleUpsell>
1825+
)}
18601826
</div>
18611827
</div>
18621828
)}

webview-ui/src/components/chat/TaskHeader.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,10 @@ const TaskHeader = ({
112112
)}
113113
<div
114114
className={cn(
115-
"px-2.5 pt-2.5 pb-2 flex flex-col gap-1.5 relative z-1 cursor-pointer",
115+
"px-3 pt-2.5 pb-2 flex flex-col gap-1.5 relative z-1 cursor-pointer",
116116
"bg-vscode-input-background hover:bg-vscode-input-background/90",
117117
"text-vscode-foreground/80 hover:text-vscode-foreground",
118-
"shadow-sm shadow-black/30 rounded-md",
118+
"shadow-sm shadow-black/30 rounded-xl",
119119
hasTodos && "border-b-0",
120120
)}
121121
onClick={(e) => {
@@ -163,7 +163,9 @@ const TaskHeader = ({
163163
</div>
164164
</div>
165165
{!isTaskExpanded && contextWindow > 0 && (
166-
<div className="flex items-center gap-2 text-sm" onClick={(e) => e.stopPropagation()}>
166+
<div
167+
className="flex items-center gap-2 text-sm text-muted-foreground/70"
168+
onClick={(e) => e.stopPropagation()}>
167169
<StandardTooltip
168170
content={
169171
<div className="space-y-1">

webview-ui/src/components/chat/__tests__/ChatView.spec.tsx

Lines changed: 9 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,39 +1319,20 @@ describe("ChatView - DismissibleUpsell Display Tests", () => {
13191319
expect(queryByTestId("dismissible-upsell")).not.toBeInTheDocument()
13201320
})
13211321

1322-
it("shows DismissibleUpsell when user is not authenticated and has run 4 or more tasks", async () => {
1322+
it("shows DismissibleUpsell when user is not authenticated and has run 6 or more tasks", async () => {
13231323
const { getByTestId } = renderChatView()
13241324

13251325
// Hydrate state with user not authenticated and 4 tasks
13261326
mockPostMessage({
13271327
cloudIsAuthenticated: false,
13281328
taskHistory: [
1329-
{ id: "1", ts: Date.now() - 3000 },
1330-
{ id: "2", ts: Date.now() - 2000 },
1331-
{ id: "3", ts: Date.now() - 1000 },
1332-
{ id: "4", ts: Date.now() },
1333-
],
1334-
clineMessages: [], // No active task
1335-
})
1336-
1337-
// Wait for component to render and show DismissibleUpsell
1338-
await waitFor(() => {
1339-
expect(getByTestId("dismissible-upsell")).toBeInTheDocument()
1340-
})
1341-
})
1342-
1343-
it("shows DismissibleUpsell when user is not authenticated and has run 5 tasks", async () => {
1344-
const { getByTestId } = renderChatView()
1345-
1346-
// Hydrate state with user not authenticated and 5 tasks
1347-
mockPostMessage({
1348-
cloudIsAuthenticated: false,
1349-
taskHistory: [
1350-
{ id: "1", ts: Date.now() - 4000 },
1351-
{ id: "2", ts: Date.now() - 3000 },
1352-
{ id: "3", ts: Date.now() - 2000 },
1353-
{ id: "4", ts: Date.now() - 1000 },
1354-
{ id: "5", ts: Date.now() },
1329+
{ id: "1", ts: Date.now() - 6000 },
1330+
{ id: "2", ts: Date.now() - 5000 },
1331+
{ id: "3", ts: Date.now() - 4000 },
1332+
{ id: "4", ts: Date.now() - 3000 },
1333+
{ id: "5", ts: Date.now() - 2000 },
1334+
{ id: "6", ts: Date.now() - 1000 },
1335+
{ id: "7", ts: Date.now() },
13551336
],
13561337
clineMessages: [], // No active task
13571338
})
@@ -1415,7 +1396,7 @@ describe("ChatView - DismissibleUpsell Display Tests", () => {
14151396
expect(getByTestId("roo-tips")).toBeInTheDocument()
14161397
})
14171398

1418-
it("shows RooTips when user has fewer than 4 tasks (instead of DismissibleUpsell)", () => {
1399+
it("shows RooTips when user has fewer than 6 tasks (instead of DismissibleUpsell)", () => {
14191400
const { queryByTestId, getByTestId } = renderChatView()
14201401

14211402
// Hydrate state with user not authenticated but fewer than 4 tasks

webview-ui/src/components/history/HistoryPreview.tsx

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,21 @@ const HistoryPreview = () => {
1515
}
1616

1717
return (
18-
<div className="flex flex-col gap-3">
18+
<div className="flex flex-col gap-1">
19+
<div className="flex flex-wrap items-center justify-between mt-4 mb-2">
20+
<h2 className="font-semibold text-lg grow m-0">{t("history:recentTasks")}</h2>
21+
<button
22+
onClick={handleViewAllHistory}
23+
className="text-base text-vscode-descriptionForeground hover:text-vscode-textLink-foreground transition-colors cursor-pointer"
24+
aria-label={t("history:viewAllHistory")}>
25+
{t("history:viewAllHistory")}
26+
</button>
27+
</div>
1928
{tasks.length !== 0 && (
2029
<>
21-
{tasks.slice(0, 3).map((item) => (
30+
{tasks.slice(0, 4).map((item) => (
2231
<TaskItem key={item.id} item={item} variant="compact" />
2332
))}
24-
<button
25-
onClick={handleViewAllHistory}
26-
className="text-base text-vscode-descriptionForeground hover:text-vscode-textLink-foreground transition-colors cursor-pointer text-center w-full"
27-
aria-label={t("history:viewAllHistory")}>
28-
{t("history:viewAllHistory")}
29-
</button>
3033
</>
3134
)}
3235
</div>

webview-ui/src/components/history/TaskItem.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ const TaskItem = ({
4747
key={item.id}
4848
data-testid={`task-item-${item.id}`}
4949
className={cn(
50-
"cursor-pointer group bg-vscode-editor-background rounded relative overflow-hidden border border-transparent hover:bg-vscode-list-hoverBackground transition-colors",
50+
"cursor-pointer group bg-vscode-editor-background rounded-xl relative overflow-hidden border border-transparent hover:bg-vscode-editor-foreground/10 transition-colors",
5151
className,
5252
)}
5353
onClick={handleClick}>
@@ -70,7 +70,7 @@ const TaskItem = ({
7070
<div className="flex-1 min-w-0">
7171
<div
7272
className={cn(
73-
"overflow-hidden whitespace-pre-wrap text-vscode-foreground text-ellipsis line-clamp-2",
73+
"overflow-hidden whitespace-pre-wrap font-light text-vscode-foreground text-ellipsis line-clamp-3",
7474
{
7575
"text-base": !isCompact,
7676
},

webview-ui/src/components/history/TaskItemFooter.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export interface TaskItemFooterProps {
1616
const TaskItemFooter: React.FC<TaskItemFooterProps> = ({ item, variant, isSelectionMode = false, onDelete }) => {
1717
return (
1818
<div className="text-xs text-vscode-descriptionForeground flex justify-between items-center">
19-
<div className="flex gap-2 items-center text-vscode-descriptionForeground/60">
19+
<div className="flex gap-1 items-center text-vscode-descriptionForeground/60">
2020
{/* Datetime with time-ago format */}
2121
<StandardTooltip content={new Date(item.ts).toLocaleString()}>
2222
<span className="first-letter:uppercase">{formatTimeAgo(item.ts)}</span>
@@ -32,7 +32,7 @@ const TaskItemFooter: React.FC<TaskItemFooterProps> = ({ item, variant, isSelect
3232

3333
{/* Action Buttons for non-compact view */}
3434
{!isSelectionMode && (
35-
<div className="flex flex-row gap-0 items-center text-vscode-descriptionForeground/60 hover:text-vscode-descriptionForeground">
35+
<div className="flex flex-row gap-0 -mx-2 items-center text-vscode-descriptionForeground/60 hover:text-vscode-descriptionForeground">
3636
<CopyButton itemTask={item.task} />
3737
{variant === "full" && <ExportButton itemId={item.id} />}
3838
{onDelete && <DeleteButton itemId={item.id} onDelete={onDelete} />}

webview-ui/src/components/history/__tests__/HistoryPreview.spec.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,11 @@ describe("HistoryPreview", () => {
100100
const { container } = render(<HistoryPreview />)
101101

102102
// Should render the container but no task items
103-
expect(container.firstChild).toHaveClass("flex", "flex-col", "gap-3")
103+
expect(container.firstChild).toHaveClass("flex", "flex-col", "gap-1")
104104
expect(screen.queryByTestId(/task-item-/)).not.toBeInTheDocument()
105105
})
106106

107-
it("renders up to 3 tasks when tasks are available", () => {
107+
it("renders up to 4 tasks when tasks are available", () => {
108108
mockUseTaskSearch.mockReturnValue({
109109
tasks: mockTasks,
110110
searchQuery: "",
@@ -123,7 +123,7 @@ describe("HistoryPreview", () => {
123123
expect(screen.getByTestId("task-item-task-1")).toBeInTheDocument()
124124
expect(screen.getByTestId("task-item-task-2")).toBeInTheDocument()
125125
expect(screen.getByTestId("task-item-task-3")).toBeInTheDocument()
126-
expect(screen.queryByTestId("task-item-task-4")).not.toBeInTheDocument()
126+
expect(screen.getByTestId("task-item-task-4")).toBeInTheDocument()
127127
expect(screen.queryByTestId("task-item-task-5")).not.toBeInTheDocument()
128128
expect(screen.queryByTestId("task-item-task-6")).not.toBeInTheDocument()
129129
})
@@ -226,6 +226,6 @@ describe("HistoryPreview", () => {
226226

227227
const { container } = render(<HistoryPreview />)
228228

229-
expect(container.firstChild).toHaveClass("flex", "flex-col", "gap-3")
229+
expect(container.firstChild).toHaveClass("flex", "flex-col", "gap-1")
230230
})
231231
})

webview-ui/src/components/history/__tests__/TaskItem.spec.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,6 @@ describe("TaskItem", () => {
107107
)
108108

109109
const taskItem = screen.getByTestId("task-item-1")
110-
expect(taskItem).toHaveClass("hover:bg-vscode-list-hoverBackground")
110+
expect(taskItem).toHaveClass("hover:bg-vscode-editor-foreground/10")
111111
})
112112
})

webview-ui/src/components/welcome/RooHero.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const RooHero = () => {
77
})
88

99
return (
10-
<div className="flex flex-col items-center justify-center pb-4 forced-color-adjust-none">
10+
<div className="pb-4 forced-color-adjust-none">
1111
<div
1212
style={{
1313
backgroundColor: "var(--vscode-foreground)",
@@ -18,7 +18,7 @@ const RooHero = () => {
1818
maskRepeat: "no-repeat",
1919
maskSize: "contain",
2020
}}
21-
className="mx-auto">
21+
className="mx-auto hover:animate-bounce">
2222
<img src={imagesBaseUri + "/roo-logo.svg"} alt="Roo logo" className="h-8 opacity-0" />
2323
</div>
2424
</div>

0 commit comments

Comments
 (0)