Skip to content

Commit 7daea69

Browse files
tweak(ui): add an empty state to the sidebar when no projects (anomalyco#17971)
Co-authored-by: Shoubhit Dash <shoubhit2005@gmail.com>
1 parent 0772a95 commit 7daea69

4 files changed

Lines changed: 60 additions & 38 deletions

File tree

packages/app/e2e/app/home.spec.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ import { serverNamePattern } from "../utils"
33

44
test("home renders and shows core entrypoints", async ({ page }) => {
55
await page.goto("/")
6+
const nav = page.locator('[data-component="sidebar-nav-desktop"]')
67

78
await expect(page.getByRole("button", { name: "Open project" }).first()).toBeVisible()
9+
await expect(nav.getByText("No projects open")).toBeVisible()
10+
await expect(nav.getByText("Open a project to get started")).toBeVisible()
811
await expect(page.getByRole("button", { name: serverNamePattern })).toBeVisible()
912
})
1013

packages/app/src/components/titlebar.tsx

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ export function Titlebar() {
7777

7878
const canBack = createMemo(() => history.index > 0)
7979
const canForward = createMemo(() => history.index < history.stack.length - 1)
80+
const hasProjects = createMemo(() => layout.projects.list().length > 0)
8081

8182
const back = () => {
8283
const next = backPath(history)
@@ -251,36 +252,38 @@ export function Titlebar() {
251252
</div>
252253
</div>
253254
</Show>
254-
<div
255-
class="flex items-center gap-0 transition-transform"
256-
classList={{
257-
"translate-x-0": !layout.sidebar.opened(),
258-
"-translate-x-[36px]": layout.sidebar.opened(),
259-
"duration-180 ease-out": !layout.sidebar.opened(),
260-
"duration-180 ease-in": layout.sidebar.opened(),
261-
}}
262-
>
263-
<Tooltip placement="bottom" value={language.t("common.goBack")} openDelay={2000}>
264-
<Button
265-
variant="ghost"
266-
icon="chevron-left"
267-
class="titlebar-icon w-6 h-6 p-0 box-border"
268-
disabled={!canBack()}
269-
onClick={back}
270-
aria-label={language.t("common.goBack")}
271-
/>
272-
</Tooltip>
273-
<Tooltip placement="bottom" value={language.t("common.goForward")} openDelay={2000}>
274-
<Button
275-
variant="ghost"
276-
icon="chevron-right"
277-
class="titlebar-icon w-6 h-6 p-0 box-border"
278-
disabled={!canForward()}
279-
onClick={forward}
280-
aria-label={language.t("common.goForward")}
281-
/>
282-
</Tooltip>
283-
</div>
255+
<Show when={hasProjects()}>
256+
<div
257+
class="flex items-center gap-0 transition-transform"
258+
classList={{
259+
"translate-x-0": !layout.sidebar.opened(),
260+
"-translate-x-[36px]": layout.sidebar.opened(),
261+
"duration-180 ease-out": !layout.sidebar.opened(),
262+
"duration-180 ease-in": layout.sidebar.opened(),
263+
}}
264+
>
265+
<Tooltip placement="bottom" value={language.t("common.goBack")} openDelay={2000}>
266+
<Button
267+
variant="ghost"
268+
icon="chevron-left"
269+
class="titlebar-icon w-6 h-6 p-0 box-border"
270+
disabled={!canBack()}
271+
onClick={back}
272+
aria-label={language.t("common.goBack")}
273+
/>
274+
</Tooltip>
275+
<Tooltip placement="bottom" value={language.t("common.goForward")} openDelay={2000}>
276+
<Button
277+
variant="ghost"
278+
icon="chevron-right"
279+
class="titlebar-icon w-6 h-6 p-0 box-border"
280+
disabled={!canForward()}
281+
onClick={forward}
282+
aria-label={language.t("common.goForward")}
283+
/>
284+
</Tooltip>
285+
</div>
286+
</Show>
284287
</div>
285288
</div>
286289
<div id="opencode-titlebar-left" class="flex items-center gap-3 min-w-0 px-2" />

packages/app/src/i18n/en.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,8 @@ export const dict = {
674674
"sidebar.project.recentSessions": "Recent sessions",
675675
"sidebar.project.viewAllSessions": "View all sessions",
676676
"sidebar.project.clearNotifications": "Clear notifications",
677+
"sidebar.empty.title": "No projects open",
678+
"sidebar.empty.description": "Open a project to get started",
677679

678680
"debugBar.ariaLabel": "Development performance diagnostics",
679681
"debugBar.na": "n/a",

packages/app/src/pages/layout.tsx

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1959,6 +1959,7 @@ export default function Layout(props: ParentProps) {
19591959
const merged = createMemo(() => panelProps.mobile || (panelProps.merged ?? layout.sidebar.opened()))
19601960
const hover = createMemo(() => !panelProps.mobile && panelProps.merged === false && !layout.sidebar.opened())
19611961
const popover = createMemo(() => !!panelProps.mobile || panelProps.merged === false || layout.sidebar.opened())
1962+
const empty = createMemo(() => !params.dir && layout.projects.list().length === 0)
19621963
const projectName = createMemo(() => {
19631964
const item = project()
19641965
if (!item) return ""
@@ -2011,7 +2012,26 @@ export default function Layout(props: ParentProps) {
20112012
width: panelProps.mobile ? undefined : `${Math.max(Math.max(layout.sidebar.width(), 244) - 64, 0)}px`,
20122013
}}
20132014
>
2014-
<Show when={project()}>
2015+
<Show
2016+
when={project()}
2017+
fallback={
2018+
<Show when={empty()}>
2019+
<div class="flex-1 min-h-0 -mt-4 flex items-center justify-center px-6 pb-64 text-center">
2020+
<div class="mt-8 flex max-w-60 flex-col items-center gap-6 text-center">
2021+
<div class="flex flex-col gap-3">
2022+
<div class="text-14-medium text-text-strong">{language.t("sidebar.empty.title")}</div>
2023+
<div class="text-14-regular text-text-base" style={{ "line-height": "var(--line-height-normal)" }}>
2024+
{language.t("sidebar.empty.description")}
2025+
</div>
2026+
</div>
2027+
<Button size="large" icon="folder-add-left" onClick={chooseProject}>
2028+
{language.t("command.project.open")}
2029+
</Button>
2030+
</div>
2031+
</div>
2032+
</Show>
2033+
}
2034+
>
20152035
<>
20162036
<div class="shrink-0 pl-1 py-1">
20172037
<div class="group/project flex items-start justify-between gap-2 py-2 pl-2 pr-0">
@@ -2260,13 +2280,7 @@ export default function Layout(props: ParentProps) {
22602280
helpLabel={() => language.t("sidebar.help")}
22612281
onOpenHelp={() => platform.openLink("https://opencode.ai/desktop-feedback")}
22622282
renderPanel={() =>
2263-
mobile ? (
2264-
<SidebarPanel project={currentProject} mobile />
2265-
) : (
2266-
<Show when={currentProject()}>
2267-
<SidebarPanel project={currentProject} merged />
2268-
</Show>
2269-
)
2283+
mobile ? <SidebarPanel project={currentProject} mobile /> : <SidebarPanel project={currentProject} merged />
22702284
}
22712285
/>
22722286
)

0 commit comments

Comments
 (0)