@@ -75,6 +75,9 @@ if (typeof browser === 'undefined' && typeof chrome !== 'undefined') {
7575 // Selector for page header actions (using prefix to avoid CSS module hash)
7676 const HEADER_ACTIONS_SELECTOR = '[data-component="PH_Actions"] [class*="HeaderMenu-module__menuActionsContainer"]' ;
7777
78+ // Selector for sticky header actions (appears when scrolling)
79+ const STICKY_HEADER_ACTIONS_SELECTOR = '[class*="HeaderMetadata-module__stickyContainer"] [class*="HeaderMenu-module__menuActionsContainer"]' ;
80+
7881 // Extension button marker
7982 const BOOKMARK_BUTTON_ATTR = 'data-extension-bookmark' ;
8083
@@ -122,8 +125,14 @@ if (typeof browser === 'undefined' && typeof chrome !== 'undefined') {
122125 button . setAttribute ( 'aria-label' , bookmarked ? 'Remove bookmark' : 'Bookmark issue' ) ;
123126 }
124127
128+ // Update all bookmark buttons on the page (main header and sticky header)
129+ function updateAllBookmarkButtons ( bookmarked ) {
130+ const buttons = document . querySelectorAll ( `[${ BOOKMARK_BUTTON_ATTR } ]` ) ;
131+ buttons . forEach ( button => updateBookmarkButton ( button , bookmarked ) ) ;
132+ }
133+
125134 // Handle bookmark button click
126- async function handleBookmarkClick ( button ) {
135+ async function handleBookmarkClick ( ) {
127136 const issueData = getIssueData ( ) ;
128137 if ( ! issueData ) {
129138 return ;
@@ -139,58 +148,36 @@ if (typeof browser === 'undefined' && typeof chrome !== 'undefined') {
139148 data : { id : issueData . id }
140149 } ) ;
141150 console . log ( '[GitHub Bookmarked Issues] Removed bookmark:' , issueData . id ) ;
142- updateBookmarkButton ( button , false ) ;
151+ updateAllBookmarkButtons ( false ) ;
143152 } else {
144153 // Add bookmark
145154 await browser . runtime . sendMessage ( {
146155 type : 'BOOKMARK_ISSUE' ,
147156 data : issueData
148157 } ) ;
149158 console . log ( '[GitHub Bookmarked Issues] Added bookmark:' , issueData . id ) ;
150- updateBookmarkButton ( button , true ) ;
159+ updateAllBookmarkButtons ( true ) ;
151160 }
152161 } catch ( error ) {
153162 console . error ( '[GitHub Bookmarked Issues] Failed to toggle bookmark:' , error ) ;
154163 showErrorNotification ( 'Failed to update bookmark. Please try again.' ) ;
155164 }
156165 }
157166
158- // Create and insert bookmark button
159- async function insertBookmarkButton ( ) {
160- const timestamp = performance . now ( ) . toFixed ( 1 ) ;
161- const issueData = getIssueData ( ) ;
162- if ( ! issueData ) {
163- console . log ( `[GitHub Bookmarked Issues] [${ timestamp } ms] Not on an issue page` ) ;
164- return ;
165- }
166-
167- const actionsContainer = document . querySelector ( HEADER_ACTIONS_SELECTOR ) ;
168- if ( ! actionsContainer ) {
169- console . log ( `[GitHub Bookmarked Issues] [${ timestamp } ms] Header actions not found, selector: ${ HEADER_ACTIONS_SELECTOR } ` ) ;
170- return ;
171- }
172-
173- // Check if button already exists
174- if ( document . querySelector ( `[${ BOOKMARK_BUTTON_ATTR } ]` ) ) {
175- console . log ( `[GitHub Bookmarked Issues] [${ timestamp } ms] Bookmark button already exists` ) ;
176- return ;
177- }
178-
179- console . log ( `[GitHub Bookmarked Issues] [${ timestamp } ms] Creating button, container children: ${ actionsContainer . children . length } ` ) ;
180-
181- // Create bookmark button
182- const bookmarkButton = document . createElement ( 'button' ) ;
183- bookmarkButton . setAttribute ( 'data-component' , 'IconButton' ) ;
184- bookmarkButton . setAttribute ( 'type' , 'button' ) ;
185- bookmarkButton . className = 'prc-Button-ButtonBase-c50BI prc-Button-IconButton-szpyj' ;
186- bookmarkButton . setAttribute ( 'data-loading' , 'false' ) ;
187- bookmarkButton . setAttribute ( 'data-no-visuals' , 'true' ) ;
188- bookmarkButton . setAttribute ( 'data-size' , 'medium' ) ;
189- bookmarkButton . setAttribute ( 'data-variant' , 'invisible' ) ;
190- bookmarkButton . setAttribute ( BOOKMARK_BUTTON_ATTR , 'true' ) ;
167+ // Create a bookmark button element
168+ function createBookmarkButton ( bookmarked ) {
169+ const button = document . createElement ( 'button' ) ;
170+ button . setAttribute ( 'data-component' , 'IconButton' ) ;
171+ button . setAttribute ( 'type' , 'button' ) ;
172+ button . className = 'prc-Button-ButtonBase-c50BI prc-Button-IconButton-szpyj' ;
173+ button . setAttribute ( 'data-loading' , 'false' ) ;
174+ button . setAttribute ( 'data-no-visuals' , 'true' ) ;
175+ button . setAttribute ( 'data-size' , 'medium' ) ;
176+ button . setAttribute ( 'data-variant' , 'invisible' ) ;
177+ button . setAttribute ( BOOKMARK_BUTTON_ATTR , 'true' ) ;
191178
192179 // Add inline styles to match GitHub's native icon buttons
193- bookmarkButton . style . cssText = `
180+ button . style . cssText = `
194181 border: none;
195182 background: transparent;
196183 padding: 0;
@@ -202,28 +189,57 @@ if (typeof browser === 'undefined' && typeof chrome !== 'undefined') {
202189 color: inherit;
203190 ` ;
204191
205- // Check if already bookmarked and set initial state
206- const bookmarked = await isBookmarked ( issueData . id ) ;
207- updateBookmarkButton ( bookmarkButton , bookmarked ) ;
192+ updateBookmarkButton ( button , bookmarked ) ;
193+ button . addEventListener ( 'click' , ( ) => handleBookmarkClick ( ) ) ;
194+
195+ return button ;
196+ }
197+
198+ // Insert bookmark button into a container if not already present
199+ function insertButtonIntoContainer ( container , bookmarked , containerName ) {
200+ // Check if this container already has a bookmark button
201+ if ( container . querySelector ( `[${ BOOKMARK_BUTTON_ATTR } ]` ) ) {
202+ return false ;
203+ }
204+
205+ const button = createBookmarkButton ( bookmarked ) ;
206+ container . appendChild ( button ) ;
207+
208+ const timestamp = performance . now ( ) . toFixed ( 1 ) ;
209+ console . log ( `[GitHub Bookmarked Issues] [${ timestamp } ms] Bookmark button added to ${ containerName } ` ) ;
210+ return true ;
211+ }
212+
213+ // Create and insert bookmark buttons into all available headers
214+ async function insertBookmarkButton ( ) {
215+ const timestamp = performance . now ( ) . toFixed ( 1 ) ;
216+ const issueData = getIssueData ( ) ;
217+ if ( ! issueData ) {
218+ console . log ( `[GitHub Bookmarked Issues] [${ timestamp } ms] Not on an issue page` ) ;
219+ return ;
220+ }
208221
209- // Add click handler
210- bookmarkButton . addEventListener ( 'click' , ( ) => handleBookmarkClick ( bookmarkButton ) ) ;
222+ // Find both header containers
223+ const mainHeader = document . querySelector ( HEADER_ACTIONS_SELECTOR ) ;
224+ const stickyHeader = document . querySelector ( STICKY_HEADER_ACTIONS_SELECTOR ) ;
211225
212- // Insert as last child in header actions
213- actionsContainer . appendChild ( bookmarkButton ) ;
226+ if ( ! mainHeader && ! stickyHeader ) {
227+ console . log ( `[GitHub Bookmarked Issues] [${ timestamp } ms] No header actions found` ) ;
228+ return ;
229+ }
214230
215- const insertTimestamp = performance . now ( ) . toFixed ( 1 ) ;
216- console . log ( `[GitHub Bookmarked Issues] [ ${ insertTimestamp } ms] Bookmark button added to DOM, parent: ${ actionsContainer . className } ` ) ;
231+ // Check if already bookmarked (only once for both buttons)
232+ const bookmarked = await isBookmarked ( issueData . id ) ;
217233
218- // Debug: watch for button removal (helps diagnose timing issues)
219- const removalObserver = new MutationObserver ( ( ) => {
220- if ( ! document . querySelector ( `[ ${ BOOKMARK_BUTTON_ATTR } ]` ) ) {
221- const removeTimestamp = performance . now ( ) . toFixed ( 1 ) ;
222- console . log ( `[GitHub Bookmarked Issues] [ ${ removeTimestamp } ms] Button was REMOVED from DOM` ) ;
223- removalObserver . disconnect ( ) ;
224- }
225- } ) ;
226- removalObserver . observe ( actionsContainer . parentElement || document . body , { childList : true , subtree : true } ) ;
234+ // Insert into main header if available
235+ if ( mainHeader ) {
236+ insertButtonIntoContainer ( mainHeader , bookmarked , 'main header' ) ;
237+ }
238+
239+ // Insert into sticky header if available
240+ if ( stickyHeader ) {
241+ insertButtonIntoContainer ( stickyHeader , bookmarked , 'sticky header' ) ;
242+ }
227243 }
228244
229245 // Track current URL to detect navigation
0 commit comments