tweak(ui): add an empty state to the sidebar when no projects (#17971)
Co-authored-by: Shoubhit Dash <shoubhit2005@gmail.com>
This commit is contained in:
co-authored by
Shoubhit Dash
parent
0772a95918
commit
7daea69e13
@@ -3,8 +3,11 @@ import { serverNamePattern } from "../utils"
|
|||||||
|
|
||||||
test("home renders and shows core entrypoints", async ({ page }) => {
|
test("home renders and shows core entrypoints", async ({ page }) => {
|
||||||
await page.goto("/")
|
await page.goto("/")
|
||||||
|
const nav = page.locator('[data-component="sidebar-nav-desktop"]')
|
||||||
|
|
||||||
await expect(page.getByRole("button", { name: "Open project" }).first()).toBeVisible()
|
await expect(page.getByRole("button", { name: "Open project" }).first()).toBeVisible()
|
||||||
|
await expect(nav.getByText("No projects open")).toBeVisible()
|
||||||
|
await expect(nav.getByText("Open a project to get started")).toBeVisible()
|
||||||
await expect(page.getByRole("button", { name: serverNamePattern })).toBeVisible()
|
await expect(page.getByRole("button", { name: serverNamePattern })).toBeVisible()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ export function Titlebar() {
|
|||||||
|
|
||||||
const canBack = createMemo(() => history.index > 0)
|
const canBack = createMemo(() => history.index > 0)
|
||||||
const canForward = createMemo(() => history.index < history.stack.length - 1)
|
const canForward = createMemo(() => history.index < history.stack.length - 1)
|
||||||
|
const hasProjects = createMemo(() => layout.projects.list().length > 0)
|
||||||
|
|
||||||
const back = () => {
|
const back = () => {
|
||||||
const next = backPath(history)
|
const next = backPath(history)
|
||||||
@@ -251,36 +252,38 @@ export function Titlebar() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
<div
|
<Show when={hasProjects()}>
|
||||||
class="flex items-center gap-0 transition-transform"
|
<div
|
||||||
classList={{
|
class="flex items-center gap-0 transition-transform"
|
||||||
"translate-x-0": !layout.sidebar.opened(),
|
classList={{
|
||||||
"-translate-x-[36px]": layout.sidebar.opened(),
|
"translate-x-0": !layout.sidebar.opened(),
|
||||||
"duration-180 ease-out": !layout.sidebar.opened(),
|
"-translate-x-[36px]": layout.sidebar.opened(),
|
||||||
"duration-180 ease-in": layout.sidebar.opened(),
|
"duration-180 ease-out": !layout.sidebar.opened(),
|
||||||
}}
|
"duration-180 ease-in": layout.sidebar.opened(),
|
||||||
>
|
}}
|
||||||
<Tooltip placement="bottom" value={language.t("common.goBack")} openDelay={2000}>
|
>
|
||||||
<Button
|
<Tooltip placement="bottom" value={language.t("common.goBack")} openDelay={2000}>
|
||||||
variant="ghost"
|
<Button
|
||||||
icon="chevron-left"
|
variant="ghost"
|
||||||
class="titlebar-icon w-6 h-6 p-0 box-border"
|
icon="chevron-left"
|
||||||
disabled={!canBack()}
|
class="titlebar-icon w-6 h-6 p-0 box-border"
|
||||||
onClick={back}
|
disabled={!canBack()}
|
||||||
aria-label={language.t("common.goBack")}
|
onClick={back}
|
||||||
/>
|
aria-label={language.t("common.goBack")}
|
||||||
</Tooltip>
|
/>
|
||||||
<Tooltip placement="bottom" value={language.t("common.goForward")} openDelay={2000}>
|
</Tooltip>
|
||||||
<Button
|
<Tooltip placement="bottom" value={language.t("common.goForward")} openDelay={2000}>
|
||||||
variant="ghost"
|
<Button
|
||||||
icon="chevron-right"
|
variant="ghost"
|
||||||
class="titlebar-icon w-6 h-6 p-0 box-border"
|
icon="chevron-right"
|
||||||
disabled={!canForward()}
|
class="titlebar-icon w-6 h-6 p-0 box-border"
|
||||||
onClick={forward}
|
disabled={!canForward()}
|
||||||
aria-label={language.t("common.goForward")}
|
onClick={forward}
|
||||||
/>
|
aria-label={language.t("common.goForward")}
|
||||||
</Tooltip>
|
/>
|
||||||
</div>
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="opencode-titlebar-left" class="flex items-center gap-3 min-w-0 px-2" />
|
<div id="opencode-titlebar-left" class="flex items-center gap-3 min-w-0 px-2" />
|
||||||
|
|||||||
@@ -674,6 +674,8 @@ export const dict = {
|
|||||||
"sidebar.project.recentSessions": "Recent sessions",
|
"sidebar.project.recentSessions": "Recent sessions",
|
||||||
"sidebar.project.viewAllSessions": "View all sessions",
|
"sidebar.project.viewAllSessions": "View all sessions",
|
||||||
"sidebar.project.clearNotifications": "Clear notifications",
|
"sidebar.project.clearNotifications": "Clear notifications",
|
||||||
|
"sidebar.empty.title": "No projects open",
|
||||||
|
"sidebar.empty.description": "Open a project to get started",
|
||||||
|
|
||||||
"debugBar.ariaLabel": "Development performance diagnostics",
|
"debugBar.ariaLabel": "Development performance diagnostics",
|
||||||
"debugBar.na": "n/a",
|
"debugBar.na": "n/a",
|
||||||
|
|||||||
@@ -1959,6 +1959,7 @@ export default function Layout(props: ParentProps) {
|
|||||||
const merged = createMemo(() => panelProps.mobile || (panelProps.merged ?? layout.sidebar.opened()))
|
const merged = createMemo(() => panelProps.mobile || (panelProps.merged ?? layout.sidebar.opened()))
|
||||||
const hover = createMemo(() => !panelProps.mobile && panelProps.merged === false && !layout.sidebar.opened())
|
const hover = createMemo(() => !panelProps.mobile && panelProps.merged === false && !layout.sidebar.opened())
|
||||||
const popover = createMemo(() => !!panelProps.mobile || panelProps.merged === false || layout.sidebar.opened())
|
const popover = createMemo(() => !!panelProps.mobile || panelProps.merged === false || layout.sidebar.opened())
|
||||||
|
const empty = createMemo(() => !params.dir && layout.projects.list().length === 0)
|
||||||
const projectName = createMemo(() => {
|
const projectName = createMemo(() => {
|
||||||
const item = project()
|
const item = project()
|
||||||
if (!item) return ""
|
if (!item) return ""
|
||||||
@@ -2011,7 +2012,26 @@ export default function Layout(props: ParentProps) {
|
|||||||
width: panelProps.mobile ? undefined : `${Math.max(Math.max(layout.sidebar.width(), 244) - 64, 0)}px`,
|
width: panelProps.mobile ? undefined : `${Math.max(Math.max(layout.sidebar.width(), 244) - 64, 0)}px`,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Show when={project()}>
|
<Show
|
||||||
|
when={project()}
|
||||||
|
fallback={
|
||||||
|
<Show when={empty()}>
|
||||||
|
<div class="flex-1 min-h-0 -mt-4 flex items-center justify-center px-6 pb-64 text-center">
|
||||||
|
<div class="mt-8 flex max-w-60 flex-col items-center gap-6 text-center">
|
||||||
|
<div class="flex flex-col gap-3">
|
||||||
|
<div class="text-14-medium text-text-strong">{language.t("sidebar.empty.title")}</div>
|
||||||
|
<div class="text-14-regular text-text-base" style={{ "line-height": "var(--line-height-normal)" }}>
|
||||||
|
{language.t("sidebar.empty.description")}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button size="large" icon="folder-add-left" onClick={chooseProject}>
|
||||||
|
{language.t("command.project.open")}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
}
|
||||||
|
>
|
||||||
<>
|
<>
|
||||||
<div class="shrink-0 pl-1 py-1">
|
<div class="shrink-0 pl-1 py-1">
|
||||||
<div class="group/project flex items-start justify-between gap-2 py-2 pl-2 pr-0">
|
<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) {
|
|||||||
helpLabel={() => language.t("sidebar.help")}
|
helpLabel={() => language.t("sidebar.help")}
|
||||||
onOpenHelp={() => platform.openLink("https://opencode.ai/desktop-feedback")}
|
onOpenHelp={() => platform.openLink("https://opencode.ai/desktop-feedback")}
|
||||||
renderPanel={() =>
|
renderPanel={() =>
|
||||||
mobile ? (
|
mobile ? <SidebarPanel project={currentProject} mobile /> : <SidebarPanel project={currentProject} merged />
|
||||||
<SidebarPanel project={currentProject} mobile />
|
|
||||||
) : (
|
|
||||||
<Show when={currentProject()}>
|
|
||||||
<SidebarPanel project={currentProject} merged />
|
|
||||||
</Show>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user