diff --git a/apps/web/src/components/AppSidebarLayout.tsx b/apps/web/src/components/AppSidebarLayout.tsx index f7b3209f661ac..383c6b3123e86 100644 --- a/apps/web/src/components/AppSidebarLayout.tsx +++ b/apps/web/src/components/AppSidebarLayout.tsx @@ -290,9 +290,7 @@ function SidebarControl() { const { toggleSidebar, isMobile, mobileSheetMounted } = useSidebar(); const isSidebarVisible = useSidebarVisibility(); const environmentIdentificationMode = useEnvironmentIdentificationMode(); - const stageBackdropVariant = useSidebarStageBackdropVariant( - environmentIdentificationMode === "artwork", - ); + const stageBackdropVariant = useSidebarStageBackdropVariant(environmentIdentificationMode); const shortcutLabel = shortcutLabelForCommand(keybindings, "sidebar.toggle", { context: { usagePageOpen }, }); diff --git a/apps/web/src/components/SidebarStageBackdrop.tsx b/apps/web/src/components/SidebarStageBackdrop.tsx index b272c5724feb7..9aa7ecc9af694 100644 --- a/apps/web/src/components/SidebarStageBackdrop.tsx +++ b/apps/web/src/components/SidebarStageBackdrop.tsx @@ -1,4 +1,5 @@ import { useAtomValue } from "@effect/atom-react"; +import type { EnvironmentIdentificationMode } from "@t3tools/contracts"; import { useId } from "react"; import { APP_STAGE_LABEL } from "../branding"; @@ -12,9 +13,11 @@ const STAGE_BACKDROP_VIEW_BOX = "0 0 8192 96"; export function resolveSidebarStageBackdropVariant( stageLabel: string, - enabled = true, + mode: EnvironmentIdentificationMode = "artwork", ): SidebarStageBackdropVariant | null { - if (!enabled) return null; + if (mode === "nightly-artwork") return "nightly"; + if (mode === "dev-artwork") return "dev"; + if (mode !== "artwork") return null; const normalized = stageLabel.trim().toLowerCase(); if (normalized === "nightly") return "nightly"; if (normalized === "dev") return "dev"; @@ -40,8 +43,10 @@ export function useEnvironmentStageLabel(): string { }); } -export function useSidebarStageBackdropVariant(enabled = true): SidebarStageBackdropVariant | null { - return resolveSidebarStageBackdropVariant(useEnvironmentStageLabel(), enabled); +export function useSidebarStageBackdropVariant( + mode: EnvironmentIdentificationMode, +): SidebarStageBackdropVariant | null { + return resolveSidebarStageBackdropVariant(useEnvironmentStageLabel(), mode); } export function SidebarStageBackdrop({ variant }: { variant: SidebarStageBackdropVariant }) { diff --git a/apps/web/src/components/chat/ComposerPrimaryActions.tsx b/apps/web/src/components/chat/ComposerPrimaryActions.tsx index 35af48b4de402..c612464e4812e 100644 --- a/apps/web/src/components/chat/ComposerPrimaryActions.tsx +++ b/apps/web/src/components/chat/ComposerPrimaryActions.tsx @@ -124,9 +124,7 @@ export const ComposerPrimaryActions = memo(function ComposerPrimaryActions({ }) === "queue"; const alternateAction = alternateComposerDispatchAction(followUpBehavior); const isSendDisabled = !canOperateThread || sendDisabledReason !== null; - const stageBackdropVariant = useSidebarStageBackdropVariant( - environmentIdentificationMode === "artwork", - ); + const stageBackdropVariant = useSidebarStageBackdropVariant(environmentIdentificationMode); const renderStopGenerationButton = (insidePendingAction: boolean) => ( diff --git a/apps/web/src/components/settings/AppearanceSettingsPanel.tsx b/apps/web/src/components/settings/AppearanceSettingsPanel.tsx index e0877c8574acc..08722ec2b061e 100644 --- a/apps/web/src/components/settings/AppearanceSettingsPanel.tsx +++ b/apps/web/src/components/settings/AppearanceSettingsPanel.tsx @@ -13,7 +13,8 @@ import { MIN_PANEL_ANIMATION_DURATION_MS, } from "@t3tools/contracts/settings"; import { - resolveEnvironmentIdentificationPillLabel, + resolveSidebarStageBackdropVariant, + type SidebarStageBackdropVariant, useEnvironmentStageLabel, } from "../SidebarStageBackdrop"; import { useCustomThemes } from "../../hooks/useCustomThemes"; @@ -35,10 +36,40 @@ import { TypographySection } from "./TypographySettings"; const ENVIRONMENT_IDENTIFICATION_LABELS: Record = { artwork: "Artwork", + "nightly-artwork": "Nightly artwork", + "dev-artwork": "Dev artwork", pill: "Version pill", none: "None", }; +// The default "artwork" follows the running channel, so it is labeled as that channel's art, +// or as "None" on Latest. The other channel's art is offered as a fixed choice. +function environmentIdentificationOptions( + stageVariant: SidebarStageBackdropVariant | null, +): ReadonlyArray { + if (stageVariant === "dev") { + return [ + ["artwork", "Dev artwork"], + ["nightly-artwork", "Nightly artwork"], + ["pill", "Version pill"], + ["none", "None"], + ]; + } + if (stageVariant === "nightly") { + return [ + ["artwork", "Nightly artwork"], + ["dev-artwork", "Dev artwork"], + ["pill", "Version pill"], + ["none", "None"], + ]; + } + return [ + ["artwork", "None"], + ["nightly-artwork", "Nightly artwork"], + ["dev-artwork", "Dev artwork"], + ]; +} + const CHAT_WIDTH_LABELS: Record = { comfortable: "Comfortable", wide: "Wide", @@ -61,8 +92,13 @@ export function AppearanceSettingsPanel() { const settings = useScopedSettings(); const updateSettings = useUpdateScopedSettings(); const environmentStageLabel = useEnvironmentStageLabel(); - const showEnvironmentIdentification = - resolveEnvironmentIdentificationPillLabel(environmentStageLabel) !== null; + const environmentStageVariant = resolveSidebarStageBackdropVariant(environmentStageLabel); + const environmentIdentificationOptionList = + environmentIdentificationOptions(environmentStageVariant); + const environmentIdentificationLabel = + environmentIdentificationOptionList.find( + ([value]) => value === settings.environmentIdentificationMode, + )?.[1] ?? ENVIRONMENT_IDENTIFICATION_LABELS[settings.environmentIdentificationMode]; const glassOpacityRatio = (settings.glassOpacity - MIN_GLASS_OPACITY) / (MAX_GLASS_OPACITY - MIN_GLASS_OPACITY); const glassOpacitySliderStyle = { @@ -316,52 +352,52 @@ export function AppearanceSettingsPanel() { ) : null } /> - {showEnvironmentIdentification ? ( - - updateSettings({ - environmentIdentificationMode: DEFAULT_ENVIRONMENT_IDENTIFICATION_MODE, - }) - } - /> - ) : null - } - control={ - { + const option = environmentIdentificationOptionList.find( + ([optionValue]) => optionValue === value, + ); + if (option) updateSettings({ environmentIdentificationMode: option[0] }); + }} + > + - - - {ENVIRONMENT_IDENTIFICATION_LABELS[settings.environmentIdentificationMode]} - - - - {Object.entries(ENVIRONMENT_IDENTIFICATION_LABELS).map(([value, label]) => ( - - {label} - - ))} - - - } - /> - ) : null} + {environmentIdentificationLabel} + + + {environmentIdentificationOptionList.map(([value, label]) => ( + + {label} + + ))} + + + } + />