@@ -34,26 +34,32 @@ const PROVIDERS = [
3434 } ,
3535] ;
3636
37+ // ── Exact copies from Navigation.tsx ────────────────────────────────────────
38+
3739const THEME_DARK = {
38- fg : 'rgba(255,255,255,0.85)' ,
39- fgMuted : 'rgba(255,255,255,0.55)' ,
40- sectionBorder : 'rgba(255,255,255,0.12)' ,
41- sectionShadow : '0 1px 4px rgba(0,0,0,0.5), inset 0 1px 0 rgba(255,255,255,0.05)' ,
42- sectionBg : '#0F0F0F' ,
43- elevatedBg : '#121212' ,
44- elevatedBorder : 'rgba(255,255,255,0.10)' ,
45- elevatedShadow : '0 8px 32px rgba(0,0,0,0.8), 0 0 0 1px rgba(255,255,255,0.07)' ,
40+ fg : 'rgba(255,255,255,0.85)' ,
41+ fgMuted : 'rgba(255,255,255,0.55)' ,
42+ hov : 'rgba(255,255,255,0.05)' ,
43+ sectionBorder : 'rgba(255,255,255,0.12)' ,
44+ sectionShadow : '0 1px 4px rgba(0,0,0,0.5), inset 0 1px 0 rgba(255,255,255,0.05)' ,
45+ dropdownBg : '#0F0F0F' ,
46+ dropdownBorder : 'rgba(255,255,255,0.10)' ,
47+ dropdownShadow : '0 8px 32px rgba(0,0,0,0.8), 0 0 0 1px rgba(255,255,255,0.07)' ,
48+ surface : '#0F0F0F' ,
49+ accentSoft : 'rgba(255,255,255,0.07)' ,
4650} as const ;
4751
4852const THEME_LIGHT = {
49- fg : 'rgba(0,0,0,0.85)' ,
50- fgMuted : 'rgba(0,0,0,0.55)' ,
51- sectionBorder : 'rgba(0,0,0,0.15)' ,
52- sectionShadow : '0 1px 4px rgba(0,0,0,0.1), inset 0 1px 0 rgba(255,255,255,0.55)' ,
53- sectionBg : '#d5d4d0' ,
54- elevatedBg : '#ECEBE7' ,
55- elevatedBorder : 'rgba(0,0,0,0.10)' ,
56- elevatedShadow : '0 8px 24px rgba(0,0,0,0.14)' ,
53+ fg : 'rgba(0,0,0,0.85)' ,
54+ fgMuted : 'rgba(0,0,0,0.55)' ,
55+ hov : 'rgba(0,0,0,0.04)' ,
56+ sectionBorder : 'rgba(0,0,0,0.15)' ,
57+ sectionShadow : '0 1px 4px rgba(0,0,0,0.1), inset 0 1px 0 rgba(255,255,255,0.55)' ,
58+ dropdownBg : '#dddcd8' , // exact from Navigation THEME_LIGHT
59+ dropdownBorder : 'rgba(0,0,0,0.1)' ,
60+ dropdownShadow : '0 8px 24px rgba(0,0,0,0.14)' ,
61+ surface : '#d5d4d0' , // exact: sectionBg items sit on top of dropdownBg
62+ accentSoft : 'rgba(0,0,0,0.05)' ,
5763} as const ;
5864
5965function tk ( isDark : boolean ) {
@@ -62,18 +68,25 @@ function tk(isDark: boolean) {
6268 return { ...base , ...mode } ;
6369}
6470
65- function getUnifiedControlStyle ( isDark : boolean , isActive = false ) {
71+ // Exact copy from Navigation.tsx
72+ function getSectionOpenBorder ( sectionOpen : boolean , isDark : boolean ) : string {
73+ if ( ! sectionOpen ) return tk ( isDark ) . sectionBorder ;
74+ return isDark ? 'rgba(255,255,255,0.22)' : 'rgba(0,0,0,0.22)' ;
75+ }
76+
77+ // Exact copy from Navigation.tsx
78+ function getUnifiedControlStyle ( isDark : boolean , isActive : boolean = false ) {
6679 const t = tk ( isDark ) ;
6780 return {
68- border : `1px solid ${ isActive
69- ? ( isDark ? 'rgba(255,255,255,0.22)' : 'rgba(0,0,0,0.22)' )
70- : t . sectionBorder } `,
71- background : t . sectionBg ,
81+ border : `1px solid ${ isActive ? getSectionOpenBorder ( true , isDark ) : t . sectionBorder } ` ,
82+ background : t . surface ,
7283 boxShadow : t . sectionShadow ,
7384 borderRadius : '8px' ,
7485 } ;
7586}
7687
88+ // ────────────────────────────────────────────────────────────────────────────
89+
7790const AskAIButton : React . FC < AskAIButtonProps > = ( { isDark, pageTitle, markdownContent } ) => {
7891 const [ open , setOpen ] = useState ( false ) ;
7992 const [ copied , setCopied ] = useState ( false ) ;
@@ -121,42 +134,42 @@ const AskAIButton: React.FC<AskAIButtonProps> = ({ isDark, pageTitle, markdownCo
121134 } catch { /* noop */ }
122135 } ;
123136
124- const allItems = [
125- ...PROVIDERS . map ( p => ( { id : p . id , label : p . name , onClick : ( ) => handleProviderClick ( p ) , icon : null } ) ) ,
126- { id : 'copy' , label : copied ? 'Скопировано!' : 'Копировать HTML' , onClick : handleCopy , icon : copied ? < Check size = { 13 } style = { { color : '#22c55e' , flexShrink : 0 } } /> : < Copy size = { 13 } style = { { opacity : 0.45 , flexShrink : 0 , color : t . fgMuted } } /> , disabled : ! markdownContent } ,
127- ] ;
128-
129137 return (
130138 < div ref = { ref } style = { { position : 'relative' , display : 'inline-block' } } >
131- { /* Trigger — same style as the nav section selector button */ }
139+
140+ { /* ── Trigger button — exact copy of the nav section selector button ── */ }
132141 < button
133142 onClick = { toggleOpen }
134143 style = { {
135- display : 'inline-flex' ,
144+ width : '100%' ,
145+ display : 'flex' ,
136146 alignItems : 'center' ,
137- gap : '0.5rem ' ,
147+ justifyContent : 'space-between ' ,
138148 padding : '0.4rem 0.65rem' ,
139149 fontSize : '0.875rem' ,
140- fontWeight : 500 ,
141- cursor : 'pointer' ,
142150 color : t . fg ,
143- userSelect : 'none' ,
144- lineHeight : 1 ,
151+ cursor : 'pointer' ,
145152 ...getUnifiedControlStyle ( isDark , open ) ,
146153 } }
147154 >
148- < Sparkles size = { 13 } style = { { color : t . fgMuted } } />
149- Спросить у ИИ
155+ < div style = { { display : 'flex' , alignItems : 'center' , gap : '0.5rem' , overflow : 'hidden' , minWidth : 0 , flex : 1 } } >
156+ < Sparkles size = { 13 } style = { { color : t . fgMuted , flexShrink : 0 } } />
157+ < span style = { { overflow : 'hidden' , textOverflow : 'ellipsis' , wordBreak : 'break-word' , lineHeight : 1.3 } } >
158+ Спросить у ИИ
159+ </ span >
160+ </ div >
150161 < ChevronDown
151162 size = { 12 }
152163 style = { {
153164 color : t . fgMuted ,
154- transform : open ? 'rotate(180deg)' : 'rotate(0deg)' ,
165+ flexShrink : 0 ,
166+ transform : open ? 'rotate(180deg)' : 'none' ,
155167 transition : 'transform 0.15s' ,
156168 } }
157169 />
158170 </ button >
159171
172+ { /* ── Popup — exact copy of the nav section dropdown ── */ }
160173 { open && createPortal (
161174 < div
162175 ref = { popupRef }
@@ -165,11 +178,12 @@ const AskAIButton: React.FC<AskAIButtonProps> = ({ isDark, pageTitle, markdownCo
165178 top : menuPos . top ,
166179 left : menuPos . left ,
167180 width : '210px' ,
168- // Exact match: nav section dropdown popup
181+ // From Navigation: position absolute, borderRadius 12, border elevatedBorder,
182+ // background isDark ? '#121212' : '#ECEBE7', boxShadow elevatedShadow
169183 borderRadius : '12px' ,
170- border : `1px solid ${ t . elevatedBorder } ` ,
171- background : t . elevatedBg ,
172- boxShadow : t . elevatedShadow ,
184+ border : `1px solid ${ t . dropdownBorder } ` ,
185+ background : isDark ? '#121212' : '#ECEBE7' ,
186+ boxShadow : t . dropdownShadow ,
173187 zIndex : 100020 ,
174188 overflow : 'hidden' ,
175189 animation : 'askAiIn 0.13s ease' ,
@@ -182,42 +196,35 @@ const AskAIButton: React.FC<AskAIButtonProps> = ({ isDark, pageTitle, markdownCo
182196 }
183197 ` } </ style >
184198
185- { /* Label — exact match: nav panel header label */ }
186- < div style = { {
187- padding : '9px 12px 4px' ,
188- fontSize : '0.72rem' ,
189- fontWeight : 700 ,
190- letterSpacing : '0.08em' ,
191- textTransform : 'uppercase' ,
192- color : t . fgMuted ,
193- } } >
194- Выбери ИИ
195- </ div >
199+ { /* Items — exact copy of SectionDropdown content wrapper */ }
200+ < div style = { { display : 'flex' , flexDirection : 'column' , gap : '4px' , padding : '8px' } } >
196201
197- { /* Items — exact match: SectionDropdown buttons */ }
198- < div style = { { display : 'flex' , flexDirection : 'column' , gap : '4px' , padding : '4px 8px 8px' } } >
199- { PROVIDERS . map ( p => {
200- const isActive = hoveredId === p . id ;
202+ { PROVIDERS . map ( s => {
203+ const isActive = hoveredId === s . id ;
201204 return (
202205 < button
203- key = { p . id }
204- onClick = { ( ) => handleProviderClick ( p ) }
205- onMouseEnter = { ( ) => setHoveredId ( p . id ) }
206+ key = { s . id }
207+ onClick = { ( ) => handleProviderClick ( s ) }
208+ onMouseEnter = { ( ) => setHoveredId ( s . id ) }
206209 onMouseLeave = { ( ) => setHoveredId ( null ) }
207210 style = { {
208211 width : '100%' ,
209212 display : 'flex' ,
210213 alignItems : 'center' ,
214+ gap : '0.5rem' ,
211215 padding : '0.55rem 0.7rem' ,
212216 fontSize : '0.875rem' ,
213- fontWeight : 400 ,
214217 textAlign : 'left' ,
215218 cursor : 'pointer' ,
216219 color : isActive ? t . accent : t . fg ,
220+ fontWeight : isActive ? 600 : 400 ,
221+ // exact: getUnifiedControlStyle from Navigation
217222 ...getUnifiedControlStyle ( isDark , isActive ) ,
218223 } }
219224 >
220- { p . name }
225+ < span style = { { wordBreak : 'break-word' , lineHeight : 1.3 , minWidth : 0 , overflow : 'hidden' , textOverflow : 'ellipsis' } } >
226+ { s . name }
227+ </ span >
221228 </ button >
222229 ) ;
223230 } ) }
@@ -226,7 +233,7 @@ const AskAIButton: React.FC<AskAIButtonProps> = ({ isDark, pageTitle, markdownCo
226233 < div style = { {
227234 height : '1px' ,
228235 background : isDark ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.08)' ,
229- margin : '2px 2px' ,
236+ margin : '0 2px' ,
230237 } } />
231238
232239 { /* Copy row */ }
@@ -245,18 +252,20 @@ const AskAIButton: React.FC<AskAIButtonProps> = ({ isDark, pageTitle, markdownCo
245252 gap : '0.5rem' ,
246253 padding : '0.55rem 0.7rem' ,
247254 fontSize : '0.875rem' ,
248- fontWeight : 400 ,
249255 textAlign : 'left' ,
250256 cursor : markdownContent ? 'pointer' : 'default' ,
251257 color : markdownContent ? ( isActive ? t . accent : t . fg ) : t . fgMuted ,
258+ fontWeight : isActive && markdownContent ? 600 : 400 ,
252259 ...getUnifiedControlStyle ( isDark , isActive && ! ! markdownContent ) ,
253260 } }
254261 >
255262 { copied
256263 ? < Check size = { 13 } style = { { color : '#22c55e' , flexShrink : 0 } } />
257264 : < Copy size = { 13 } style = { { opacity : 0.45 , flexShrink : 0 , color : t . fgMuted } } />
258265 }
259- { copied ? 'Скопировано!' : 'Копировать HTML' }
266+ < span style = { { wordBreak : 'break-word' , lineHeight : 1.3 } } >
267+ { copied ? 'Скопировано!' : 'Копировать HTML' }
268+ </ span >
260269 </ button >
261270 ) ;
262271 } ) ( ) }
0 commit comments