2828 # list > ul { padding-left : 0 ; }
2929 .tree-dir { display : flex; align-items : center; gap : 6px ; padding : 6px 10px ; border-radius : 10px ; cursor : pointer; color : var (--text ); }
3030 .tree-dir : hover { background : # 141936 ; }
31+ .tree-dir .submenu-open { background : # 151f3c ; border : 1px solid var (--accent ); }
3132 .tree-dir button { appearance : none; border : none; background : none; color : var (--muted ); cursor : pointer; font-size : 12px ; display : flex; align-items : center; justify-content : center; width : 18px ; }
3233 .tree-dir button : focus { outline : 1px solid var (--accent ); border-radius : 4px ; }
33- .tree-dir .folder-name { font-size : 13px ; font-weight : 600 ; }
34- .tree-dir .github-folder-icon { margin-left : 4px ; cursor : pointer; opacity : 0.6 ; transition : opacity 0.2s ; font-size : 12px ; }
35- .tree-dir .github-folder-icon : hover { opacity : 1 ; }
36- .tree-dir .add-file-icon { margin-left : 4px ; cursor : pointer; opacity : 0.6 ; transition : opacity 0.2s ; font-size : 12px ; color : # 4ade80 ; }
37- .tree-dir .add-file-icon : hover { opacity : 1 ; }
34+ .tree-dir .folder-name { font-size : 13px ; font-weight : 600 ; flex : 1 ; }
35+ .tree-dir .folder-icons { display : flex; gap : 4px ; margin-left : auto; }
36+ .tree-dir .folder-icons span { cursor : pointer; opacity : 0.6 ; transition : all 0.2s ; padding : 4px ; border-radius : 4px ; min-width : 28px ; min-height : 28px ; display : flex; align-items : center; justify-content : center; }
37+ .tree-dir .folder-icons span : hover { opacity : 1 ; background : rgba (255 , 255 , 255 , 0.05 ); }
38+ .tree-dir .add-file-icon { color : # 4ade80 ; font-weight : bold; }
39+ .tree-dir .add-file-icon : hover { background : rgba (74 , 222 , 128 , 0.1 ) !important ; }
3840 .item { display : flex; align-items : center; justify-content : space-between; gap : 8px ; padding : 6px 10px ; border-radius : 10px ; border : 1px solid transparent; background : # 12162a ; cursor : pointer; }
3941 .item : hover { border-color : var (--border ); background : # 141936 ; }
4042 .item-title { font-size : 14px ; font-weight : 600 ; }
5759 footer { max-width : 1100px ; margin : 20px auto 40px ; color : var (--muted ); font-size : 13px ; padding : 0 16px ; }
5860 .pill { display : inline-flex; align-items : center; gap : 6px ; padding : 6px 8px ; border-radius : 999px ; border : 1px solid var (--border ); background : # 11152a ; font-size : 12px ; color : var (--muted ); }
5961
60- /* Branch dropdown styling */
6162 # branchSelect optgroup {
6263 font-weight : 600 ;
6364 color : var (--muted );
9394 </ div >
9495 < div style ="display:flex; align-items:center; gap:8px; ">
9596 < div class ="pill " id ="repoPill "> Loading repo...</ div >
96- <!-- Chevron + branch select -->
9797 < label style ="display:flex; align-items:center; gap:4px; ">
9898 < span title ="Choose a branch "> ▼</ span >
9999 < select id ="branchSelect " class ="btn " style ="min-width:140px; ">
@@ -170,6 +170,8 @@ <h1 id="title" style="display:none"></h1>
170170 let currentSlug = null ;
171171 let expandedState = new Set ( ) ;
172172 let expandedStateKey = null ;
173+ let openSubmenus = new Set ( ) ;
174+ let activeSubmenuHeaders = new Set ( ) ;
173175
174176 const listEl = document . getElementById ( 'list' ) ;
175177 const contentEl = document . getElementById ( 'content' ) ;
@@ -194,12 +196,10 @@ <h1 id="title" style="display:none"></h1>
194196 const CODEX_URL_REGEX = / ^ h t t p s : \/ \/ c h a t g p t \. c o m \/ s \/ [ a - f 0 - 9 _ ] + $ / i;
195197
196198 async function resolveGistRawUrl ( gistUrl ) {
197- // If it's already a raw URL, use it directly
198199 if ( GIST_POINTER_REGEX . test ( gistUrl ) ) {
199200 return gistUrl ;
200201 }
201202
202- // Parse regular gist URLs
203203 const match = gistUrl . match ( / ^ h t t p s : \/ \/ g i s t \. g i t h u b \. c o m \/ ( [ \w - ] + ) \/ ( [ a - f 0 - 9 ] + ) \/ ? (?: # f i l e - ( [ \w . - ] + ) ) ? (?: \? f i l e = ( [ \w . - ] + ) ) ? $ / i) ;
204204 if ( ! match ) {
205205 throw new Error ( 'Invalid gist URL format' ) ;
@@ -209,10 +209,8 @@ <h1 id="title" style="display:none"></h1>
209209 const targetFile = fragmentFile || queryFile ;
210210
211211 if ( targetFile ) {
212- // Specific file requested
213212 return `https://gist.githubusercontent.com/${ user } /${ gistId } /raw/${ targetFile } ` ;
214213 } else {
215- // No specific file - fetch gist metadata to find the best file
216214 const apiUrl = `https://api.github.com/gists/${ gistId } ` ;
217215 const res = await fetch ( viaProxy ( apiUrl ) ) ;
218216 if ( ! res . ok ) {
@@ -279,6 +277,17 @@ <h1 id="title" style="display:none"></h1>
279277 } catch { }
280278 }
281279
280+ function closeAllSubmenus ( ) {
281+ openSubmenus . forEach ( submenu => {
282+ submenu . style . display = 'none' ;
283+ } ) ;
284+ activeSubmenuHeaders . forEach ( header => {
285+ header . classList . remove ( 'submenu-open' ) ;
286+ } ) ;
287+ openSubmenus . clear ( ) ;
288+ activeSubmenuHeaders . clear ( ) ;
289+ }
290+
282291 function prettyTitle ( name ) {
283292 const base = name . replace ( / \. m d $ / i, "" ) ;
284293 const addEmoji = ( s ) => {
@@ -478,6 +487,9 @@ <h1 id="title" style="display:none"></h1>
478487 label . className = 'folder-name' ;
479488 label . textContent = entry . name ;
480489
490+ const iconsContainer = document . createElement ( 'div' ) ;
491+ iconsContainer . className = 'folder-icons' ;
492+
481493 const ghIcon = document . createElement ( 'span' ) ;
482494 ghIcon . className = 'github-folder-icon' ;
483495 ghIcon . textContent = '🗂️' ;
@@ -492,17 +504,99 @@ <h1 id="title" style="display:none"></h1>
492504 addIcon . className = 'add-file-icon' ;
493505 addIcon . textContent = '+' ;
494506 addIcon . title = 'Create new file in this directory' ;
495- addIcon . addEventListener ( 'click' , ( ev ) => {
496- ev . stopPropagation ( ) ;
507+
508+ const submenu = document . createElement ( 'div' ) ;
509+ submenu . style . position = 'absolute' ;
510+ submenu . style . background = 'var(--card)' ;
511+ submenu . style . border = '1px solid var(--border)' ;
512+ submenu . style . borderRadius = '8px' ;
513+ submenu . style . padding = '6px 0' ;
514+ submenu . style . boxShadow = '0 4px 10px rgba(0,0,0,0.3)' ;
515+ submenu . style . display = 'none' ;
516+ submenu . style . zIndex = '10' ;
517+
518+ const makeMenuItem = ( label , emoji , onClick ) => {
519+ const item = document . createElement ( 'div' ) ;
520+ item . textContent = `${ emoji } ${ label } ` ;
521+ item . style . padding = '6px 14px' ;
522+ item . style . cursor = 'pointer' ;
523+ item . style . fontSize = '13px' ;
524+ item . style . color = 'var(--text)' ;
525+ item . addEventListener ( 'mouseenter' , ( ) => item . style . background = '#1a1f35' ) ;
526+ item . addEventListener ( 'mouseleave' , ( ) => item . style . background = 'transparent' ) ;
527+ item . addEventListener ( 'click' , ( e ) => {
528+ e . stopPropagation ( ) ;
529+ submenu . style . display = 'none' ;
530+ onClick ( ) ;
531+ } ) ;
532+ return item ;
533+ } ;
534+
535+ submenu . appendChild ( makeMenuItem ( "Prompt (blank)" , "📝" , ( ) => {
497536 const newFilePath = entry . path ? `${ entry . path } /new-prompt.md` : 'new-prompt.md' ;
498- const ghUrl = `https://github.com/${ currentOwner } /${ currentRepo } /new/${ currentBranch } ?filename=${ newFilePath } ` ;
537+ const ghUrl = `https://github.com/${ currentOwner } /${ currentRepo } /new/${ currentBranch } ?filename=${ encodeURIComponent ( newFilePath ) } ` ;
499538 window . open ( ghUrl , '_blank' , 'noopener,noreferrer' ) ;
539+ } ) ) ;
540+
541+ submenu . appendChild ( makeMenuItem ( "Conversation (template)" , "💬" , ( ) => {
542+ const template = `**Conversation Link (Codex, Jules, etc):** [https://chatgpt.com/s/...]\n\n### Prompt\n[paste your full prompt here]\n\n### Additional Info\n[context, notes, or follow-up thoughts]\n` ;
543+ const encoded = encodeURIComponent ( template ) ;
544+ const newFilePath = entry . path ? `${ entry . path } /new-conversation.md` : 'new-conversation.md' ;
545+ const ghUrl = `https://github.com/${ currentOwner } /${ currentRepo } /new/${ currentBranch } ?filename=${ encodeURIComponent ( newFilePath ) } &value=${ encoded } ` ;
546+ window . open ( ghUrl , '_blank' , 'noopener,noreferrer' ) ;
547+ } ) ) ;
548+
549+ document . body . appendChild ( submenu ) ;
550+
551+ addIcon . addEventListener ( 'click' , ( ev ) => {
552+ ev . stopPropagation ( ) ;
553+
554+ const wasOpen = submenu . style . display === 'block' ;
555+ closeAllSubmenus ( ) ;
556+
557+ if ( ! wasOpen ) {
558+ const rect = addIcon . getBoundingClientRect ( ) ;
559+
560+ submenu . style . display = 'block' ;
561+ submenu . style . visibility = 'hidden' ;
562+ const submenuRect = submenu . getBoundingClientRect ( ) ;
563+
564+ let left = rect . right ;
565+ let top = rect . top ;
566+
567+ if ( left + submenuRect . width > window . innerWidth - 10 ) {
568+ left = rect . left - submenuRect . width ;
569+ }
570+
571+ if ( top + submenuRect . height > window . innerHeight - 10 ) {
572+ top = rect . bottom - submenuRect . height ;
573+ }
574+
575+ if ( left < 10 ) {
576+ left = 10 ;
577+ }
578+
579+ if ( top < 10 ) {
580+ top = 10 ;
581+ }
582+
583+ submenu . style . left = left + 'px' ;
584+ submenu . style . top = top + 'px' ;
585+ submenu . style . visibility = 'visible' ;
586+ openSubmenus . add ( submenu ) ;
587+ header . classList . add ( 'submenu-open' ) ;
588+ activeSubmenuHeaders . add ( header ) ;
589+ }
500590 } ) ;
591+
592+ document . addEventListener ( 'click' , ( ) => closeAllSubmenus ( ) ) ;
593+
594+ iconsContainer . appendChild ( ghIcon ) ;
595+ iconsContainer . appendChild ( addIcon ) ;
501596
502597 header . appendChild ( toggle ) ;
503598 header . appendChild ( label ) ;
504- header . appendChild ( ghIcon ) ;
505- header . appendChild ( addIcon ) ;
599+ header . appendChild ( iconsContainer ) ;
506600 li . appendChild ( header ) ;
507601
508602 const childList = document . createElement ( 'ul' ) ;
@@ -903,7 +997,7 @@ <h1 id="title" style="display:none"></h1>
903997 }
904998
905999 if ( userBranches . length > 0 ) {
906- const showUsers = localStorage . getItem ( 'showUserBranches' ) !== 'false' ; // default: true
1000+ const showUsers = localStorage . getItem ( 'showUserBranches' ) !== 'false' ;
9071001 const userGroup = document . createElement ( 'optgroup' ) ;
9081002
9091003 const userHeaderOpt = document . createElement ( 'option' ) ;
0 commit comments