diff --git a/.github/workflows/program-classification-validator.yml b/.github/workflows/program-classification-validator.yml index 923cbc0046..34ef75b54a 100644 --- a/.github/workflows/program-classification-validator.yml +++ b/.github/workflows/program-classification-validator.yml @@ -89,26 +89,30 @@ jobs: // ------------------------------------ // Metadata - new template format // ------------------------------------ + + const normalizedBody = body.replace(/\r\n/g, '\n'); + const has = (re) => re.test(normalizedBody); if ( - body.includes('- [x] gssoc26') || - body.includes('program: gssoc') || - body.includes('- [x] gssoc') + has(/\bprogram\s*:\s*gssoc\b/i) || + has(/^\s*[-*]\s*\[x\]\s*(gssoc26|gssoc|i am contributing under gssoc|i am participating via gssoc)\b/im) || + has(/\bprogram\n\s*gssoc\b/i) ) { actualPrograms.add('gssoc'); } if ( - body.includes('- [x] nsoc26') || - body.includes('program: nsoc') || - body.includes('- [x] nsoc') + has(/\bprogram\s*:\s*nsoc\b/i) || + has(/^\s*[-*]\s*\[x\]\s*(nsoc26|nsoc|i am contributing under nsoc|i am participating via nsoc)\b/im) || + has(/\bprogram\n\s*nsoc\b/i) ) { actualPrograms.add('nsoc'); } if ( - body.includes('- [x] general contribution') || - body.includes('program: general') + has(/\bprogram\s*:\s*general\b/i) || + has(/^\s*[-*]\s*\[x\]\s*(general contribution|i am a general contributor)\b/im) || + has(/\bprogram\n\s*general\b/i) ) { hasGeneralContribution = true; } diff --git a/index.html b/index.html index 68c91fcccd..158d461e21 100644 --- a/index.html +++ b/index.html @@ -38,35 +38,62 @@ } - - - - - @@ -75,7 +102,12 @@ // Theme restoration - runs early to prevent FOUC (function(){ try { - if (localStorage.getItem('theme') === 'dark') { + const savedTheme = localStorage.getItem('theme'); + if (savedTheme === 'dark') { + document.documentElement.classList.add('dark'); + } else if (savedTheme === 'light') { + document.documentElement.classList.remove('dark'); + } else if (globalThis.matchMedia?.('(prefers-color-scheme: dark)').matches) { document.documentElement.classList.add('dark'); } } catch(e) { diff --git a/src/js/app.js b/src/js/app.js index d1c9415db2..e2ca2cf414 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -109,9 +109,26 @@ const CONTACT_TIPS = { // ══════════════════════════════════════════════ (function initTheme() { try { - const saved = localStorage.getItem('theme') || 'light'; - document.documentElement.classList.toggle('dark', saved === 'dark'); + const saved = localStorage.getItem('theme'); + if (saved === 'dark') { + document.documentElement.classList.add('dark'); + } else if (saved === 'light') { + document.documentElement.classList.remove('dark'); + } else if (globalThis.matchMedia?.('(prefers-color-scheme: dark)').matches) { + document.documentElement.classList.add('dark'); + } else { + document.documentElement.classList.remove('dark'); + } updateThemeIcon(); + + if (globalThis.matchMedia) { + globalThis.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => { + if (!localStorage.getItem('theme')) { + document.documentElement.classList.toggle('dark', e.matches); + updateThemeIcon(); + } + }); + } } catch (e) { console.warn('Theme init failed:', e); }