Skip to content

Commit 9422154

Browse files
committed
Add announcement banner
1 parent 52e2cce commit 9422154

File tree

3 files changed

+89
-18
lines changed

3 files changed

+89
-18
lines changed

cli/src/chat.tsx

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
21
import { useKeyboard } from '@opentui/react'
2+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
33
import { useShallow } from 'zustand/react/shallow'
44

55
import { routeUserPrompt } from './commands/router'
6-
import { MessageWithAgents } from './components/message-with-agents'
7-
import { useFeedbackStore } from './state/feedback-store'
8-
import type { MultilineInputHandle } from './components/multiline-input'
6+
import { AnnouncementBanner } from './components/announcement-banner'
97
import { ChatInputBar } from './components/chat-input-bar'
10-
import { getStatusIndicatorState } from './utils/status-indicator-state'
8+
import { MessageWithAgents } from './components/message-with-agents'
119
import { StatusBar } from './components/status-bar'
1210
import { SLASH_COMMANDS } from './data/slash-commands'
1311
import { useAgentValidation } from './hooks/use-agent-validation'
@@ -20,26 +18,26 @@ import { useInputHistory } from './hooks/use-input-history'
2018
import { useKeyboardHandlers } from './hooks/use-keyboard-handlers'
2119
import { useMessageQueue } from './hooks/use-message-queue'
2220
import { useMessageVirtualization } from './hooks/use-message-virtualization'
21+
import { useQueueControls } from './hooks/use-queue-controls'
22+
import { useQueueUi } from './hooks/use-queue-ui'
2323
import { useChatScrollbox } from './hooks/use-scroll-management'
2424
import { useSendMessage } from './hooks/use-send-message'
2525
import { useSuggestionEngine } from './hooks/use-suggestion-engine'
2626
import { useSuggestionMenuHandlers } from './hooks/use-suggestion-menu-handlers'
2727
import { useTerminalDimensions } from './hooks/use-terminal-dimensions'
2828
import { useTheme } from './hooks/use-theme'
2929
import { useValidationBanner } from './hooks/use-validation-banner'
30-
import { useQueueUi } from './hooks/use-queue-ui'
31-
import { useQueueControls } from './hooks/use-queue-controls'
32-
import { logger } from './utils/logger'
33-
import { AnalyticsEvent } from '@codebuff/common/constants/analytics-events'
3430
import { useChatStore } from './state/chat-store'
31+
import { useFeedbackStore } from './state/feedback-store'
3532
import { createChatScrollAcceleration } from './utils/chat-scroll-accel'
3633
import { loadLocalAgents } from './utils/local-agent-registry'
3734
import { buildMessageTree } from './utils/message-tree-utils'
35+
import { getStatusIndicatorState } from './utils/status-indicator-state'
3836
import { computeInputLayoutMetrics } from './utils/text-layout'
3937
import { createMarkdownPalette } from './utils/theme-system'
40-
import { BORDER_CHARS } from './utils/ui-constants'
4138

42-
import type { ChatMessage, ContentBlock } from './types/chat'
39+
import type { MultilineInputHandle } from './components/multiline-input'
40+
import type { ContentBlock } from './types/chat'
4341
import type { SendMessageFn } from './types/contracts/send-message'
4442
import type { User } from './utils/auth'
4543
import type { FileTreeNode } from '@codebuff/common/util/file'
@@ -120,6 +118,8 @@ export const Chat = ({
120118
resetChatStore,
121119
sessionCreditsUsed,
122120
setRunState,
121+
isAnnouncementVisible,
122+
setIsAnnouncementVisible,
123123
} = useChatStore(
124124
useShallow((store) => ({
125125
inputValue: store.inputValue,
@@ -153,6 +153,8 @@ export const Chat = ({
153153
resetChatStore: store.reset,
154154
sessionCreditsUsed: store.sessionCreditsUsed,
155155
setRunState: store.setRunState,
156+
isAnnouncementVisible: store.isAnnouncementVisible,
157+
setIsAnnouncementVisible: store.setIsAnnouncementVisible,
156158
})),
157159
)
158160

@@ -290,7 +292,7 @@ export const Chat = ({
290292

291293
return block
292294
})
293-
295+
294296
// Return original array reference if nothing changed
295297
return foundTarget ? result : blocks
296298
}
@@ -329,7 +331,7 @@ export const Chat = ({
329331
const contentHeight = scrollbox.scrollHeight
330332
const viewportHeight = scrollbox.viewport.height
331333
const isOverflowing = contentHeight > viewportHeight
332-
334+
333335
// Only update state if overflow status actually changed
334336
if (hasOverflowRef.current !== isOverflowing) {
335337
hasOverflowRef.current = isOverflowing
@@ -346,8 +348,6 @@ export const Chat = ({
346348
}
347349
}, [])
348350

349-
350-
351351
const inertialScrollAcceleration = useMemo(
352352
() => createChatScrollAcceleration(),
353353
[],
@@ -850,7 +850,10 @@ export const Chat = ({
850850
stickyStart="bottom"
851851
scrollX={false}
852852
scrollbarOptions={{ visible: false }}
853-
verticalScrollbarOptions={{ visible: !isStreaming && hasOverflow, trackOptions: { width: 1 } }}
853+
verticalScrollbarOptions={{
854+
visible: !isStreaming && hasOverflow,
855+
trackOptions: { width: 1 },
856+
}}
854857
{...appliedScrollboxProps}
855858
style={{
856859
flexGrow: 1,
@@ -878,6 +881,10 @@ export const Chat = ({
878881
},
879882
}}
880883
>
884+
{isAnnouncementVisible && (
885+
<AnnouncementBanner onClose={() => setIsAnnouncementVisible(false)} />
886+
)}
887+
881888
{headerContent}
882889
{virtualizationNotice}
883890
{topLevelMessages.map((message, idx) => {
@@ -954,7 +961,6 @@ export const Chat = ({
954961
handleExitFeedback={handleExitFeedback}
955962
handleSubmit={handleSubmit}
956963
/>
957-
958964
</box>
959965

960966
{validationBanner}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { Button } from './button'
2+
import { useTerminalDimensions } from '../hooks/use-terminal-dimensions'
3+
import { useTheme } from '../hooks/use-theme'
4+
import { BORDER_CHARS } from '../utils/ui-constants'
5+
6+
interface AnnouncementBannerProps {
7+
onClose: () => void
8+
}
9+
10+
export const AnnouncementBanner = ({ onClose }: AnnouncementBannerProps) => {
11+
const { terminalWidth } = useTerminalDimensions()
12+
const theme = useTheme()
13+
14+
return (
15+
<box
16+
key={terminalWidth}
17+
style={{
18+
width: '100%',
19+
borderStyle: 'single',
20+
borderColor: theme.secondary,
21+
flexDirection: 'row',
22+
justifyContent: 'space-between',
23+
alignItems: 'flex-start',
24+
paddingLeft: 1,
25+
paddingRight: 1,
26+
paddingTop: 0,
27+
paddingBottom: 0,
28+
marginTop: 0,
29+
marginBottom: 0,
30+
flexShrink: 0,
31+
}}
32+
border={['top', 'bottom', 'left', 'right']}
33+
customBorderChars={BORDER_CHARS}
34+
>
35+
<text
36+
style={{
37+
fg: theme.foreground,
38+
wrapMode: 'word',
39+
flexShrink: 1,
40+
marginRight: 3,
41+
}}
42+
>
43+
Codebuff has been updated with new UI! Tell us how it's going with{' '}
44+
<span style={{ fg: theme.secondary }}>/feedback</span>.
45+
<br />
46+
Revert to the old Codebuff with:{' '}
47+
<span style={{ fg: theme.secondary }}>
48+
npm install -g codebuff@legacy
49+
</span>
50+
</text>
51+
<Button onClick={onClose}>
52+
<text style={{ fg: theme.secondary }}>x</text>
53+
</Button>
54+
</box>
55+
)
56+
}

cli/src/state/chat-store.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import { immer } from 'zustand/middleware/immer'
44

55
import { clamp } from '../utils/math'
66

7-
import type { RunState } from '@codebuff/sdk'
87
import type { ChatMessage } from '../types/chat'
98
import type { AgentMode } from '../utils/constants'
9+
import type { RunState } from '@codebuff/sdk'
1010

1111
export type InputValue = {
1212
text: string
@@ -32,6 +32,7 @@ export type ChatStoreState = {
3232
sessionCreditsUsed: number
3333
runState: RunState | null
3434
isUsageVisible: boolean
35+
isAnnouncementVisible: boolean
3536
}
3637

3738
type ChatStoreActions = {
@@ -61,6 +62,7 @@ type ChatStoreActions = {
6162
addSessionCredits: (credits: number) => void
6263
setRunState: (runState: RunState | null) => void
6364
setIsUsageVisible: (visible: boolean) => void
65+
setIsAnnouncementVisible: (visible: boolean) => void
6466
reset: () => void
6567
}
6668

@@ -84,6 +86,7 @@ const initialState: ChatStoreState = {
8486
sessionCreditsUsed: 0,
8587
runState: null,
8688
isUsageVisible: false,
89+
isAnnouncementVisible: true,
8790
}
8891

8992
export const useChatStore = create<ChatStore>()(
@@ -192,6 +195,11 @@ export const useChatStore = create<ChatStore>()(
192195
state.isUsageVisible = visible
193196
}),
194197

198+
setIsAnnouncementVisible: (visible) =>
199+
set((state) => {
200+
state.isAnnouncementVisible = visible
201+
}),
202+
195203
reset: () =>
196204
set((state) => {
197205
state.messages = initialState.messages.slice()
@@ -213,6 +221,7 @@ export const useChatStore = create<ChatStore>()(
213221
? castDraft(initialState.runState)
214222
: null
215223
state.isUsageVisible = initialState.isUsageVisible
224+
state.isAnnouncementVisible = initialState.isAnnouncementVisible
216225
}),
217226
})),
218227
)

0 commit comments

Comments
 (0)