@@ -24,6 +24,8 @@ interface LimitedLandingPanelProps {
2424 sessionCounterText : string
2525 /** True when the shared per-day quota is fully spent. Disables the CTA. */
2626 isQuotaExhausted : boolean
27+ /** Plain-text explanation shown instead of the CTA when quota is exhausted. */
28+ exhaustedMessageText : string
2729 /** Max vertical rows the panel may occupy. When its content is taller the
2830 * panel scrolls (scrollbar shown) instead of letting flexbox compress the
2931 * bordered button onto its own border. */
@@ -42,6 +44,7 @@ export const LimitedLandingPanel: React.FC<LimitedLandingPanelProps> = ({
4244 sessionCounter,
4345 sessionCounterText,
4446 isQuotaExhausted,
47+ exhaustedMessageText,
4548 maxHeight,
4649} ) => {
4750 const theme = useTheme ( )
@@ -52,16 +55,22 @@ export const LimitedLandingPanel: React.FC<LimitedLandingPanelProps> = ({
5255
5356 // Rendered height of the panel, matching the JSX below row-for-row so the
5457 // scroll budget is exact: name + warning (each wrap-aware) + the counter
55- // line with its 1-row top/bottom margins + the 3-row bordered button.
58+ // line with its 1-row top/bottom margins + either the 3-row bordered button
59+ // or the exhausted-quota message.
60+ const exhaustedTitleText = 'Daily session limit reached'
5661 const wrappedRows = ( text : string ) =>
5762 Math . max ( 1 , Math . ceil ( text . length / contentMaxWidth ) )
63+ const BUTTON_ROWS = 3 // 2 border rows + label
64+ const actionRows = isQuotaExhausted
65+ ? wrappedRows ( exhaustedTitleText ) + wrappedRows ( exhaustedMessageText )
66+ : BUTTON_ROWS
5867 const contentHeight =
5968 wrappedRows ( model . displayName ) +
6069 ( model . warning ? wrappedRows ( model . warning ) : 0 ) +
6170 1 /* counter marginTop */ +
6271 wrappedRows ( sessionCounterText ) +
6372 1 /* counter marginBottom */ +
64- 3 /* button: 2 border rows + label */
73+ actionRows
6574 const needsScroll = contentHeight > maxHeight
6675 const viewportHeight = Math . max ( 1 , Math . min ( contentHeight , maxHeight ) )
6776
@@ -72,14 +81,17 @@ export const LimitedLandingPanel: React.FC<LimitedLandingPanelProps> = ({
7281 // 'center'` on the parent can center the whole block again.
7382 const BUTTON_LABEL = 'Start session Enter'
7483 const BUTTON_CHROME = 6 // 2 border + 4 padding (paddingLeft/Right 2)
84+ const actionWidth = isQuotaExhausted
85+ ? Math . max ( exhaustedTitleText . length , exhaustedMessageText . length )
86+ : BUTTON_LABEL . length + BUTTON_CHROME
7587 const panelWidth =
7688 Math . min (
7789 contentMaxWidth ,
7890 Math . max (
7991 model . displayName . length ,
8092 model . warning ?. length ?? 0 ,
8193 sessionCounterText . length ,
82- BUTTON_LABEL . length + BUTTON_CHROME ,
94+ actionWidth ,
8395 ) ,
8496 ) + ( needsScroll ? 1 : 0 ) /* scrollbar gutter */
8597
@@ -159,30 +171,43 @@ export const LimitedLandingPanel: React.FC<LimitedLandingPanelProps> = ({
159171 >
160172 { sessionCounter }
161173 </ text >
162- < Button
163- onClick = { start }
164- style = { {
165- borderStyle : 'single' ,
166- borderColor : interactable ? theme . primary : theme . border ,
167- paddingLeft : 2 ,
168- paddingRight : 2 ,
169- flexShrink : 0 ,
170- } }
171- border = { [ 'top' , 'bottom' , 'left' , 'right' ] }
172- >
173- < text
174- style = { { fg : interactable ? theme . foreground : theme . muted } }
175- attributes = { TextAttributes . BOLD }
174+ { isQuotaExhausted ? (
175+ < >
176+ < text style = { { wrapMode : 'word' , flexShrink : 0 } } >
177+ < span fg = { theme . secondary } attributes = { TextAttributes . BOLD } >
178+ { exhaustedTitleText }
179+ </ span >
180+ </ text >
181+ < text style = { { fg : theme . muted , wrapMode : 'word' , flexShrink : 0 } } >
182+ { exhaustedMessageText }
183+ </ text >
184+ </ >
185+ ) : (
186+ < Button
187+ onClick = { start }
188+ style = { {
189+ borderStyle : 'single' ,
190+ borderColor : interactable ? theme . primary : theme . border ,
191+ paddingLeft : 2 ,
192+ paddingRight : 2 ,
193+ flexShrink : 0 ,
194+ } }
195+ border = { [ 'top' , 'bottom' , 'left' , 'right' ] }
176196 >
177- { pending ? (
178- 'Starting…'
179- ) : (
180- < >
181- Start session< span fg = { theme . muted } > { ' Enter' } </ span >
182- </ >
183- ) }
184- </ text >
185- </ Button >
197+ < text
198+ style = { { fg : interactable ? theme . foreground : theme . muted } }
199+ attributes = { TextAttributes . BOLD }
200+ >
201+ { pending ? (
202+ 'Starting…'
203+ ) : (
204+ < >
205+ Start session< span fg = { theme . muted } > { ' Enter' } </ span >
206+ </ >
207+ ) }
208+ </ text >
209+ </ Button >
210+ ) }
186211 </ scrollbox >
187212 )
188213}
0 commit comments