tui: surface a dismissible new-interface notice and tighten settings copy for clarity

Users who were migrated to the new interface will now see a dismissible notice in Settings explaining the old interface was phased out, so they are not surprised by the change. The new-interface toggle is also visually elevated with a card style so it is easier to find. Settings labels and descriptions across General have been rewritten to be shorter and more direct, so it is quicker to understand what each option controls. The "New" badge color is also adjusted for better readability.
This commit is contained in:
usrnk1 2026-07-13 12:01:19 +02:00
commit 446510a6a9
6 changed files with 89 additions and 37 deletions

View file

@ -251,7 +251,7 @@ export const SettingsGeneral: Component = () => {
}) })
const InterfaceSection = () => ( const InterfaceSection = () => (
<div class="flex flex-col gap-1"> <div class="flex flex-col gap-4">
<SettingsList> <SettingsList>
<SettingsRow <SettingsRow
title={ title={
@ -280,6 +280,23 @@ export const SettingsGeneral: Component = () => {
</div> </div>
</SettingsRow> </SettingsRow>
</SettingsList> </SettingsList>
<Show when={!settings.general.newInterfaceNoticeDismissed()}>
<SettingsList>
<SettingsRow
title={language.t("settings.general.row.newInterfaceNotice.title")}
description={language.t("settings.general.row.newInterfaceNotice.description", {
date: new Intl.DateTimeFormat(language.intl(), { month: "long", day: "numeric" }).format(
oldInterfaceSunset,
),
})}
>
<Button size="small" variant="ghost" onClick={settings.general.dismissNewInterfaceNotice}>
{language.t("settings.general.row.newInterfaceNotice.dismiss")}
</Button>
</SettingsRow>
</SettingsList>
</Show>
</div> </div>
) )

View file

@ -230,34 +230,53 @@ export const SettingsGeneralV2: Component<{
const InterfaceSection = () => ( const InterfaceSection = () => (
<div class="settings-v2-section"> <div class="settings-v2-section">
<SettingsListV2> <div class="settings-v2-interface-feature">
<SettingsRowV2 <SettingsListV2>
title={ <SettingsRowV2
<span class="flex items-center gap-2"> title={
{language.t("settings.general.row.newInterface.title")} <span class="flex items-center gap-2">
<Tag variant="accent">{language.t("settings.general.row.newInterface.badge")}</Tag> {language.t("settings.general.row.newInterface.title")}
</span> <Tag variant="accent">{language.t("settings.general.row.newInterface.badge")}</Tag>
} </span>
description={language.t("settings.general.row.newInterface.description", { }
date: new Intl.DateTimeFormat(language.intl(), { month: "long", day: "numeric" }).format( description={language.t("settings.general.row.newInterface.description", {
oldInterfaceSunset, date: new Intl.DateTimeFormat(language.intl(), { month: "long", day: "numeric" }).format(
), oldInterfaceSunset,
})} ),
> })}
<div data-action="settings-new-layout-designs"> >
<Switch <div data-action="settings-new-layout-designs">
checked={settings.general.newLayoutDesigns()} <Switch
onChange={(checked) => { checked={settings.general.newLayoutDesigns()}
settings.general.setNewLayoutDesigns(checked) onChange={(checked) => {
if (checked) return settings.general.setNewLayoutDesigns(checked)
void import("@/components/dialog-settings").then((module) => { if (checked) return
void dialog.show(() => <module.DialogSettings />) void import("@/components/dialog-settings").then((module) => {
}) void dialog.show(() => <module.DialogSettings />)
}} })
/> }}
</div> />
</SettingsRowV2> </div>
</SettingsListV2> </SettingsRowV2>
</SettingsListV2>
</div>
<Show when={!settings.general.newInterfaceNoticeDismissed()}>
<SettingsListV2>
<SettingsRowV2
title={language.t("settings.general.row.newInterfaceNotice.title")}
description={language.t("settings.general.row.newInterfaceNotice.description", {
date: new Intl.DateTimeFormat(language.intl(), { month: "long", day: "numeric" }).format(
oldInterfaceSunset,
),
})}
>
<ButtonV2 size="small" variant="ghost-muted" onClick={settings.general.dismissNewInterfaceNotice}>
{language.t("settings.general.row.newInterfaceNotice.dismiss")}
</ButtonV2>
</SettingsRowV2>
</SettingsListV2>
</Show>
</div> </div>
) )

View file

@ -90,6 +90,11 @@
box-shadow: inset 0 0 0 0.5px var(--v2-border-border-muted); box-shadow: inset 0 0 0 0.5px var(--v2-border-border-muted);
} }
.settings-v2-interface-feature [data-component="settings-v2-list"] {
background-color: var(--v2-background-bg-base);
box-shadow: var(--v2-elevation-raised);
}
[data-component="settings-v2-row"] { [data-component="settings-v2-row"] {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
@ -128,7 +133,7 @@
} }
[data-slot="settings-v2-row-description"] { [data-slot="settings-v2-row-description"] {
font-size: 11px; font-size: 13px;
font-weight: 440; font-weight: 440;
line-height: 1; line-height: 1;
color: var(--v2-text-text-muted); color: var(--v2-text-text-muted);

View file

@ -34,6 +34,7 @@ export interface Settings {
showCustomAgents: boolean showCustomAgents: boolean
mobileTitlebarPosition: "top" | "bottom" mobileTitlebarPosition: "top" | "bottom"
newLayoutDesigns?: boolean newLayoutDesigns?: boolean
newInterfaceNoticeDismissed?: boolean
} }
appearance: { appearance: {
fontSize: number fontSize: number
@ -254,6 +255,13 @@ export const { use: useSettings, provider: SettingsProvider } = createSimpleCont
setNewLayoutDesigns(value: boolean) { setNewLayoutDesigns(value: boolean) {
setStore("general", "newLayoutDesigns", value) setStore("general", "newLayoutDesigns", value)
}, },
newInterfaceNoticeDismissed: withFallback(
() => store.general?.newInterfaceNoticeDismissed,
false,
),
dismissNewInterfaceNotice() {
setStore("general", "newInterfaceNoticeDismissed", true)
},
}, },
visibility: { visibility: {
fileTree: visible(showFileTree), fileTree: visible(showFileTree),

View file

@ -855,9 +855,8 @@ export const dict = {
"settings.general.row.language.title": "Language", "settings.general.row.language.title": "Language",
"settings.general.row.language.description": "Change the display language for OpenCode", "settings.general.row.language.description": "Change the display language for OpenCode",
"settings.general.row.shell.title": "Terminal Shell", "settings.general.row.shell.title": "Terminal shell",
"settings.general.row.shell.description": "settings.general.row.shell.description": "Shell used by the terminal and agent tools",
"Choose the shell used for your terminal. Compatible shells are also used for agent tool calls.",
"settings.general.row.shell.autoDefault": "Auto (Default)", "settings.general.row.shell.autoDefault": "Auto (Default)",
"settings.general.row.shell.terminalOnly": "terminal only", "settings.general.row.shell.terminalOnly": "terminal only",
"settings.general.row.appearance.title": "Appearance", "settings.general.row.appearance.title": "Appearance",
@ -889,8 +888,9 @@ export const dict = {
"settings.general.row.mobileTitlebarBottom.title": "Bottom navigation", "settings.general.row.mobileTitlebarBottom.title": "Bottom navigation",
"settings.general.row.mobileTitlebarBottom.description": "settings.general.row.mobileTitlebarBottom.description":
"Place the title bar and session tabs at the bottom of the screen on mobile", "Place the title bar and session tabs at the bottom of the screen on mobile",
"settings.general.row.showCustomAgents.title": "Custom agents", "settings.general.row.showCustomAgents.title": "Show agent",
"settings.general.row.showCustomAgents.description": "Show the agent picker in the composer", "settings.general.row.showCustomAgents.description":
"Switch between agents in the composer. When hidden, defaults to Build agent.",
"settings.general.row.reasoningSummaries.title": "Show reasoning summaries", "settings.general.row.reasoningSummaries.title": "Show reasoning summaries",
"settings.general.row.reasoningSummaries.description": "Display model reasoning summaries in the timeline", "settings.general.row.reasoningSummaries.description": "Display model reasoning summaries in the timeline",
"settings.general.row.shellToolPartsExpanded.title": "Expand shell tool parts", "settings.general.row.shellToolPartsExpanded.title": "Expand shell tool parts",
@ -902,7 +902,10 @@ export const dict = {
"settings.general.row.newInterface.title": "Use the new interface", "settings.general.row.newInterface.title": "Use the new interface",
"settings.general.row.newInterface.badge": "New", "settings.general.row.newInterface.badge": "New",
"settings.general.row.newInterface.description": "settings.general.row.newInterface.description":
"A redesigned layout, tabs, composer and new home. Old interface goes away on {{date}}.", "New layout, tabs, composer and home. Switch back until {{date}}.",
"settings.general.row.newInterfaceNotice.title": "You're now using the new interface",
"settings.general.row.newInterfaceNotice.description": "The old interface was phased out on {{date}}.",
"settings.general.row.newInterfaceNotice.dismiss": "Dismiss",
"settings.general.row.pinchZoom.title": "Pinch to zoom", "settings.general.row.pinchZoom.title": "Pinch to zoom",
"settings.general.row.pinchZoom.description": "Allow trackpad pinch and Ctrl-scroll gestures to zoom", "settings.general.row.pinchZoom.description": "Allow trackpad pinch and Ctrl-scroll gestures to zoom",

View file

@ -29,5 +29,5 @@
[data-component="tag"][data-variant="accent"] { [data-component="tag"][data-variant="accent"] {
border: 0; border: 0;
background: var(--v2-background-bg-accent); background: var(--v2-background-bg-accent);
color: var(--v2-text-text-inverse); color: var(--v2-text-text-contrast);
} }