Merge pull request #64598 from NousResearch/bb/desktop-backdrop-toggle

feat(desktop): add a chat backdrop on/off toggle
This commit is contained in:
brooklyn! 2026-07-14 17:04:33 -04:00 committed by GitHub
commit f7198a2055
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 49 additions and 1 deletions

View file

@ -12,6 +12,7 @@ import { Check, Download, Loader2, Palette, Trash2 } from '@/lib/icons'
import { selectableCardClass } from '@/lib/selectable-card'
import { normalize } from '@/lib/text'
import { cn } from '@/lib/utils'
import { $backdrop, setBackdrop } from '@/store/backdrop'
import { $embedAllowed, $embedMode, clearEmbedAllowed, type EmbedMode, setEmbedMode } from '@/store/embed-consent'
import { $activeGatewayProfile, $profiles, normalizeProfileKey } from '@/store/profile'
import { $toolViewMode, setToolViewMode } from '@/store/tool-view'
@ -248,6 +249,7 @@ export function AppearanceSettings() {
const embedMode = useStore($embedMode)
const embedAllowed = useStore($embedAllowed)
const translucency = useStore($translucency)
const backdrop = useStore($backdrop)
const installs = useStore($marketplaceInstalls)
const profiles = useStore($profiles)
const activeProfileKey = normalizeProfileKey(useStore($activeGatewayProfile))
@ -451,6 +453,24 @@ export function AppearanceSettings() {
title={a.translucencyTitle}
/>
<ListRow
action={
<SegmentedControl
onChange={id => {
triggerHaptic('selection')
setBackdrop(id === 'on')
}}
options={[
{ id: 'off', label: t.common.off },
{ id: 'on', label: t.common.on }
]}
value={backdrop ? 'on' : 'off'}
/>
}
description={a.backdropDesc}
title={a.backdropTitle}
/>
<ListRow
action={
<SegmentedControl

View file

@ -1,6 +1,9 @@
import { useStore } from '@nanostores/react'
import { Leva, useControls } from 'leva'
import { type CSSProperties, useEffect, useState } from 'react'
import { $backdrop } from '@/store/backdrop'
const BLEND_MODES = [
'normal',
'multiply',
@ -25,6 +28,7 @@ const assetPath = (path: string) => `${import.meta.env.BASE_URL}${path.replace(/
export function Backdrop() {
const [controlsOpen, setControlsOpen] = useState(false)
const on = useStore($backdrop)
useEffect(() => {
if (!import.meta.env.DEV) {
@ -87,7 +91,7 @@ export function Backdrop() {
<>
<Leva collapsed hidden={!import.meta.env.DEV || !controlsOpen} titleBar={{ title: 'backdrop', drag: true }} />
{statue.enabled && (
{on && statue.enabled && (
<div
aria-hidden
className="pointer-events-none absolute inset-0 z-2"

View file

@ -392,6 +392,8 @@ export const en: Translations = {
`Scales text and controls across the whole app. Cmd/Ctrl with +, - and 0 also works. Current: ${percent}%.`,
translucencyTitle: 'Window Translucency',
translucencyDesc: 'See your desktop through the whole window. macOS and Windows only.',
backdropTitle: 'Chat Backdrop',
backdropDesc: 'The faint statue image behind the conversation.',
embedsTitle: 'Inline Embeds',
embedsDesc:
'Rich previews load from third-party sites (YouTube, X, …). Ask shows a placeholder until you allow each one; Always loads them automatically; Off keeps plain links.',

View file

@ -297,6 +297,8 @@ export const ja = defineLocale({
`アプリ全体の文字と UI を拡大縮小します。Cmd/Ctrl と +、-、0 でも変更できます。現在: ${percent}%`,
translucencyTitle: 'ウィンドウの透過',
translucencyDesc: 'ウィンドウ全体を透過させてデスクトップを表示します。macOS と Windows のみ。',
backdropTitle: 'チャット背景',
backdropDesc: '会話の背後に表示される淡い彫像の画像。',
embedsTitle: 'インライン埋め込み',
embedsDesc:
'リッチプレビューは第三者サイトYouTube、X など)から読み込まれます。確認は許可するまでプレースホルダーを表示し、常には自動で読み込み、オフはリンクのままにします。',

View file

@ -311,6 +311,8 @@ export interface Translations {
uiScaleDesc: (percent: number) => string
translucencyTitle: string
translucencyDesc: string
backdropTitle: string
backdropDesc: string
embedsTitle: string
embedsDesc: string
embedsAsk: string

View file

@ -290,6 +290,8 @@ export const zhHant = defineLocale({
`縮放整個應用程式的文字與介面。也可使用 Cmd/Ctrl 加 +、- 或 0 調整。目前:${percent}%`,
translucencyTitle: '視窗透明',
translucencyDesc: '讓整個視窗透出桌面。僅支援 macOS 與 Windows。',
backdropTitle: '聊天背景',
backdropDesc: '對話後方那張淡淡的雕像圖片。',
embedsTitle: '內嵌預覽',
embedsDesc:
'豐富預覽會從第三方網站YouTube、X 等)載入。詢問會在你允許前顯示佔位符;一律會自動載入;關閉則保留純連結。',

View file

@ -381,6 +381,8 @@ export const zh: Translations = {
`缩放整个应用的文字和界面。也可使用 Cmd/Ctrl 加 +、- 或 0 调整。当前:${percent}%`,
translucencyTitle: '窗口透明',
translucencyDesc: '让整个窗口透出桌面。仅支持 macOS 和 Windows。',
backdropTitle: '聊天背景',
backdropDesc: '对话后方那张淡淡的雕像图片。',
embedsTitle: '内嵌预览',
embedsDesc:
'富预览会从第三方网站YouTube、X 等)加载。询问会在你允许前显示占位符;总是会自动加载;关闭则保留纯链接。',

View file

@ -0,0 +1,14 @@
import { atom } from 'nanostores'
import { persistBoolean, storedBoolean } from '@/lib/storage'
const KEY = 'hermes.desktop.backdrop.v1'
/** Whether the faint statue image renders behind the chat transcript. */
export const $backdrop = atom(storedBoolean(KEY, true))
$backdrop.subscribe(on => persistBoolean(KEY, on))
export function setBackdrop(on: boolean) {
$backdrop.set(on)
}