feat(app): hide project names in tabs by default (#46778)

This commit is contained in:
Brendan Allan
2026-09-02 17:23:18 +08:00
committed by GitHub
Unverified
parent eead95e712
commit 91a4c7bc32
9 changed files with 57 additions and 9 deletions
@@ -42,7 +42,7 @@ test("mobile project selection and drawer navigation preserve session identity",
const drawer = page.locator('[data-slot="mobile-tabs-drawer"]')
await trigger.click()
await expect(trigger).toHaveAttribute("aria-expanded", "true")
await expect(drawer.locator('[data-slot="tab-project"]')).toHaveText([fixture.project.name, fixture.project.name])
await expect(drawer.locator('[data-slot="tab-project"]')).toHaveCount(0)
const settings = drawer.getByRole("button", { name: "Settings", exact: true })
const help = drawer.getByRole("button", { name: "Help", exact: true })
await expect(settings).toBeVisible()
@@ -149,7 +149,7 @@ test("vertical tabs show project details, resize, and navigate", async ({ page }
({ server, sessionA, sessionB }) => {
localStorage.setItem(
"settings.v3",
JSON.stringify({ appearance: { tabLayout: "vertical" }, general: { showStatus: true } }),
JSON.stringify({ appearance: { tabLayout: "vertical", showProjectName: true }, general: { showStatus: true } }),
)
localStorage.setItem(
"opencode.window.browser.dat:tabs",
@@ -219,7 +219,7 @@ test("vertical tabs show project details, resize, and navigate", async ({ page }
await expect(tabB).toBeVisible()
})
test("appearance experimental setting switches tab orientation", async ({ page }) => {
test("appearance experimental settings control vertical tab details", async ({ page }) => {
await mockServer(page)
await page.addInitScript(
({ server, sessionA }) => {
@@ -251,6 +251,12 @@ test("appearance experimental setting switches tab orientation", async ({ page }
await expect(layout).toContainText("Vertical")
await expect(page.locator('[data-slot="vertical-tabs-sidebar"]')).toBeVisible()
await expect(page.locator('[data-slot="titlebar-tabs"]')).toHaveCount(0)
const projectNames = page.locator('[data-slot="vertical-tabs-sidebar"] [data-slot="tab-project"]')
await expect(projectNames).toHaveCount(0)
const projectNameSwitch = settings.getByRole("switch", { name: "Show project names", exact: true })
await settings.locator('[data-action="settings-show-project-name"] [data-slot="switch-control"]').click()
await expect(projectNameSwitch).toBeChecked()
await expect(projectNames).toHaveText(["tab-project"])
await expect(settings.getByRole("tablist")).toHaveCSS("width", "240px")
await page.setViewportSize({ width: 920, height: 720 })
@@ -274,6 +280,9 @@ test("appearance experimental setting switches tab orientation", async ({ page }
await page.reload()
const href = `/server/${base64Encode(server)}/session/${sessionA.id}`
await page.getByRole("button", { name: "Tabs", exact: true }).click()
await expect(page.locator('[data-slot="mobile-tabs-drawer"] [data-slot="tab-project"]')).toHaveText([
"tab-project",
])
await expect(
page
.locator('[data-slot="mobile-tabs-drawer"]')
+2
View File
@@ -911,6 +911,8 @@ export const dict = {
"settings.appearance.row.tabs.description": "Choose how session tabs are arranged",
"settings.appearance.row.tabs.horizontal": "Horizontal",
"settings.appearance.row.tabs.vertical": "Vertical",
"settings.appearance.row.projectName.title": "Show project names",
"settings.appearance.row.projectName.description": "Show project names in vertical tabs and the mobile tab drawer",
"settings.notifications.description": "Choose when to receive notifications and hear sounds",
"settings.shortcuts.description": "Customize shortcuts for common actions",
"settings.servers.description": "Manage server connections",
@@ -1,6 +1,7 @@
import { Component, createMemo } from "solid-js"
import { Select } from "@opencode-ai/ui/select"
import { TextInput } from "@opencode-ai/ui/text-input"
import { Switch } from "@opencode-ai/ui/switch"
import { useLanguage } from "@/runtime/i18n/language"
import { ExternalLink } from "@/runtime/platform/external-link"
import { SettingsList } from "@/settings/list"
@@ -149,6 +150,20 @@ export const SettingsAppearance: Component = () => {
onSelect={(option) => option && appearance.tabs.select(option)}
/>
</SettingsRow>
<SettingsRow
title={language.t("settings.appearance.row.projectName.title")}
description={language.t("settings.appearance.row.projectName.description")}
>
<div data-action="settings-show-project-name">
<Switch
checked={appearance.projectName.current()}
onChange={appearance.projectName.set}
hideLabel
>
{language.t("settings.appearance.row.projectName.title")}
</Switch>
</div>
</SettingsRow>
</SettingsList>
</div>
</div>
@@ -85,6 +85,10 @@ export function createAppearanceSettingsController() {
current: settings.appearance.tabLayout,
select: settings.appearance.setTabLayout,
},
projectName: {
current: settings.appearance.showProjectName,
set: settings.appearance.setShowProjectName,
},
}
}
+10 -2
View File
@@ -101,7 +101,14 @@ describe("settings schema", () => {
terminalPlacement: "side",
followUpBehavior: "steer",
},
appearance: { fontSize: 14, mono: "", sans: "", terminal: "", tabLayout: "horizontal" },
appearance: {
fontSize: 14,
mono: "",
sans: "",
terminal: "",
tabLayout: "horizontal",
showProjectName: false,
},
keybinds: {},
permissions: { autoApprove: false },
workspaces: { defaultDestination: "last-used", lastUsed: {} },
@@ -126,7 +133,7 @@ describe("settings schema", () => {
reasoningMode: 3,
followUpBehavior: "invalid",
},
appearance: { fontSize: "large", mono: "Custom Mono", tabLayout: "vertical" },
appearance: { fontSize: "large", mono: "Custom Mono", tabLayout: "vertical", showProjectName: true },
permissions: { autoApprove: true },
workspaces: { defaultDestination: "new", lastUsed: { good: "workspace", bad: true } },
keybinds: { good: "ctrl+k", bad: 3 },
@@ -146,6 +153,7 @@ describe("settings schema", () => {
sans: "",
terminal: "",
tabLayout: "vertical",
showProjectName: true,
})
expect(settings.permissions.autoApprove).toBe(true)
expect(settings.workspaces).toEqual({ defaultDestination: "new", lastUsed: { good: "workspace" } })
+9 -1
View File
@@ -95,6 +95,7 @@ const appearanceSchema = Persistence.struct({
sans: Schema.String,
terminal: Schema.String,
tabLayout: Schema.Literals(["horizontal", "vertical"]),
showProjectName: Schema.Boolean,
})
const permissionsSchema = Persistence.struct({
@@ -179,7 +180,7 @@ export const defaultSettings: Settings = {
terminalPlacement: "side",
followUpBehavior: "steer",
},
appearance: { fontSize: 14, mono: "", sans: "", terminal: "", tabLayout: "horizontal" },
appearance: { fontSize: 14, mono: "", sans: "", terminal: "", tabLayout: "horizontal", showProjectName: false },
keybinds: {},
permissions: { autoApprove: false },
workspaces: { defaultDestination: "last-used", lastUsed: {} },
@@ -327,6 +328,13 @@ export const { use: useSettings, provider: SettingsProvider } = createSimpleCont
setTabLayout(value: TabLayout) {
setStore("appearance", "tabLayout", value)
},
showProjectName: withFallback(
() => store.appearance?.showProjectName,
defaultSettings.appearance.showProjectName,
),
setShowProjectName(value: boolean) {
setStore("appearance", "showProjectName", value)
},
},
keybinds: {
get: (action: string) => store.keybinds?.[action],
+2 -2
View File
@@ -15,11 +15,11 @@
background: linear-gradient(var(--tab-overlay), var(--tab-overlay)), var(--tab-base);
}
[data-titlebar-tab][data-orientation="vertical"]:has([data-slot="project-avatar-slot"]) {
[data-titlebar-tab][data-orientation="vertical"]:has([data-slot="tab-project"]) {
height: 45px;
}
[data-titlebar-tab][data-orientation="vertical"]:has([data-slot="project-avatar-slot"]) [data-slot="tab-link"] {
[data-titlebar-tab][data-orientation="vertical"]:has([data-slot="tab-project"]) [data-slot="tab-link"] {
display: grid;
grid-template-columns: 16px minmax(0, 1fr);
grid-template-rows: repeat(2, var(--line-height-compact));
+3 -1
View File
@@ -14,6 +14,7 @@ import { SessionTabAvatar } from "@/shell/layout/session-tab-avatar"
import { SessionProgressIndicatorV2 } from "@opencode-ai/session-ui/v2/session-progress-indicator-v2"
import type { SessionInfo } from "@opencode-ai/client/promise"
import { sessionLabel } from "@/session/title"
import { useSettings } from "@/settings/model"
import { canOpenTabRename, forwardTabRef } from "./tab-gesture"
import { TabPreviewPopover } from "./tab-popover"
import "./tab-nav.css"
@@ -39,6 +40,7 @@ export function TabNavItem(props: {
orientation?: "horizontal" | "vertical"
}) {
const language = useLanguage()
const settings = useSettings()
const [menu, setMenu] = createStore({ open: false, rename: false })
const [editing, setEditing] = createSignal(false)
const [titleOverflowing, setTitleOverflowing] = createSignal(false)
@@ -298,7 +300,7 @@ export function TabNavItem(props: {
event.preventDefault()
}}
/>
<Show when={props.orientation === "vertical" && projectName()}>
<Show when={props.orientation === "vertical" && settings.appearance.showProjectName() && projectName()}>
{(name) => (
<span data-slot="tab-project" dir="auto">
{name()}