1515var isIndexPage = ! ! document . getElementById ( "recommend-form" ) ;
1616// PROJECT_ID is set by the server only on detail pages, so if it's missing we're elsewhere
1717var isDetailPage = typeof PROJECT_ID !== "undefined" ;
18+ var modal = document . getElementById ( 'github-modal-overlay' ) ;
19+ var openModalBtn = document . getElementById ( 'btn-show-github' ) ; // The trigger in your main form
20+ var closeModalBtn = document . getElementById ( 'btn-close-github' ) ;
21+ var fetchBtn = document . getElementById ( 'btn-fetch-github' ) ;
22+ var githubInput = document . getElementById ( 'github-username' ) ;
23+ var errorMsg = document . getElementById ( 'github-modal-error' ) ;
1824
1925
2026// ============================================================
@@ -350,6 +356,9 @@ if (isIndexPage) {
350356 }
351357
352358 function syncSkillsHiddenInput ( ) {
359+ if ( ! skillsHidden ) {
360+ var skillsHidden = document . getElementById ( "skills" ) ;
361+ }
353362 // Keep the hidden <input> in sync for form serialisation
354363 // The API expects a comma-separated string, so join the array that way
355364 skillsHidden . value = selectedSkills . join ( ", " ) ;
@@ -715,6 +724,66 @@ if (isDetailPage) {
715724 }
716725} // end isDetailPage
717726
727+ if (
728+ openModalBtn &&
729+ closeModalBtn &&
730+ modal &&
731+ githubInput &&
732+ fetchBtn &&
733+ errorMsg
734+ ) {
735+ // 1. Open Github Input Modal
736+ openModalBtn . addEventListener ( 'click' , ( e ) => {
737+ e . preventDefault ( ) ;
738+ modal . classList . add ( 'active' ) ;
739+ githubInput . focus ( ) ;
740+ } ) ;
741+
742+ // 2. Close Github Input Modal
743+ const closeGithubModal = ( ) => {
744+ modal . classList . remove ( 'active' ) ;
745+ githubInput . value = '' ;
746+ errorMsg . textContent = '' ;
747+ } ;
748+
749+ closeModalBtn . addEventListener ( 'click' , closeGithubModal ) ;
750+
751+ // Close on clicking outside the card
752+ modal . addEventListener ( 'click' , ( e ) => {
753+ if ( e . target === modal ) closeGithubModal ( ) ;
754+ } ) ;
755+
756+ // 3. Fetch Skills Logic
757+ fetchBtn . addEventListener ( 'click' , async ( ) => {
758+ const username = githubInput . value . trim ( ) ;
759+ if ( ! username ) return ;
760+
761+ fetchBtn . disabled = true ;
762+ fetchBtn . textContent = 'Syncing...' ;
763+
764+ try {
765+ const response = await fetch ( `https://api.github.com/users/${ username } /repos` ) ;
766+ if ( ! response . ok ) throw new Error ( ) ;
767+
768+ const repos = await response . json ( ) ;
769+ const langs = [ ...new Set ( repos . map ( r => r . language ) . filter ( Boolean ) ) ] ;
770+
771+ if ( langs . length > 0 ) {
772+ langs . forEach ( lang => {
773+ if ( typeof addSkill === 'function' ) addSkill ( lang ) ;
774+ } ) ;
775+ closeGithubModal ( ) ;
776+ } else {
777+ errorMsg . textContent = "No public languages found." ;
778+ }
779+ } catch ( err ) {
780+ errorMsg . textContent = err . message ?? "Failed to fetch skills" ;
781+ } finally {
782+ fetchBtn . disabled = false ;
783+ fetchBtn . textContent = 'Fetch Skills' ;
784+ }
785+ } ) ;
786+ }
718787
719788/* ---- Scroll-to-top button ---- */
720789
@@ -743,4 +812,4 @@ function scrollToTop() {
743812if ( scrollTopBtn ) {
744813 window . addEventListener ( 'scroll' , handleScroll ) ;
745814 scrollTopBtn . addEventListener ( 'click' , scrollToTop ) ;
746- }
815+ }
0 commit comments