Skip to content
91 changes: 70 additions & 21 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -1275,7 +1275,7 @@
</header>

<!-- Mobile Menu Overlay -->
<div id="mobileMenu" class="fixed inset-0 z-50 hidden md:hidden" style="z-index:60;" role="dialog" aria-modal="true" aria-label="Navigation menu">

Check warning on line 1278 in index.html

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use <dialog> instead of the dialog role to ensure accessibility across all devices.

See more on https://sonarcloud.io/project/issues?id=S3DFX-CYBER_GSoC-Org-Finder-&issues=AZ8ykBN4gn42AMKbVI5B&open=AZ8ykBN4gn42AMKbVI5B&pullRequest=1992
<!-- Backdrop -->
<div class="absolute inset-0 bg-black/60 backdrop-blur-sm" onclick="toggleMenu()" onkeydown="if(event.key==='Enter'||event.key===' ')toggleMenu()" tabindex="0" role="button" aria-label="Close menu"></div>

Expand Down Expand Up @@ -1356,6 +1356,7 @@
<div class="relative z-10 bg-white dark:bg-[#18181b] rounded-[calc(1rem-1.5px)] w-full search-border-inner flex items-center gap-2 transition-all duration-300">
<span class="material-symbols-outlined absolute left-4 top-1/2 -translate-y-1/2 text-zinc-400">search</span>
<input id="hero-search" type="text" placeholder="Search organization names..." aria-label="Search GSoC 2026 organizations" class="flex-1 bg-transparent border-0 rounded-2xl py-3 sm:py-4 pl-12 pr-4 text-sm font-medium focus:ring-0 focus:outline-none transition-all text-zinc-900 dark:text-zinc-100" />
<span class="hidden sm:inline-flex items-center gap-0.5 mr-2 px-1.5 py-0.5 rounded-md border border-zinc-300 dark:border-zinc-600 text-[10px] font-mono font-semibold text-zinc-400 dark:text-zinc-500 select-none" aria-hidden="true">⌘/Ctrl K</span>
<button id="hero-search-submit" type="button" class="mr-2 inline-flex items-center justify-center rounded-xl bg-primary px-4 py-2 text-xs sm:text-sm font-bold text-white transition-colors hover:bg-orange-600 focus:outline-none focus:ring-2 focus:ring-primary/30">
Search
</button>
Expand Down Expand Up @@ -5199,7 +5200,7 @@
}
Comment thread
greptile-apps[bot] marked this conversation as resolved.
</script>

<div class="modal-bg" id="helpModal">
<div class="modal-bg" id="helpModal" role="dialog" aria-modal="true" aria-labelledby="helpModalTitle">

Check warning on line 5203 in index.html

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use <dialog> instead of the dialog role to ensure accessibility across all devices.

See more on https://sonarcloud.io/project/issues?id=S3DFX-CYBER_GSoC-Org-Finder-&issues=AZ8tAayo_PZEko8307io&open=AZ8tAayo_PZEko8307io&pullRequest=1992
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
<div class="modal">

<button class="close-btn" onclick="closeHelpModal()" aria-label="Close keyboard shortcuts modal">
Expand All @@ -5209,7 +5210,7 @@


<div class="modal-header">
<h2>Keyboard Shortcuts</h2>
<h2 id="helpModalTitle">Keyboard Shortcuts</h2>
<p>Quick shortcuts for navigation</p>
</div>

Expand Down Expand Up @@ -5245,10 +5246,20 @@
</tr>

<tr class="shortcut-row">
<td class="py-2"><kbd>/</kbd></td>
<td class="py-2"><kbd>/</kbd> or <kbd>⌘</kbd><kbd>K</kbd></td>
<td class="py-2">Focus search bar</td>
</tr>

<tr class="shortcut-row">
<td class="py-2"><kbd>Alt</kbd><kbd>1</kbd></td>
<td class="py-2">Jump to Timeline section</td>
</tr>

<tr class="shortcut-row">
<td class="py-2"><kbd>Alt</kbd><kbd>2</kbd></td>
<td class="py-2">Jump to Organizations section</td>
</tr>


<tr class="category-row">
<td colspan="2">Actions</td>
Expand Down Expand Up @@ -5309,16 +5320,38 @@

const helpModal = document.getElementById('helpModal');
const helpBtn = document.getElementById('helpBtn');
let helpModalTriggerEl = null;

function trapHelpModalFocus(e) {
if (e.key !== 'Tab' || !helpModal) return;
const focusables = helpModal.querySelectorAll('button, [href], input, select, textarea, [tabindex="0"]');
if (!focusables.length) return;
const first = focusables[0];
const last = focusables[focusables.length - 1];
if (e.shiftKey && document.activeElement === first) {
last.focus();
e.preventDefault();
} else if (!e.shiftKey && document.activeElement === last) {
first.focus();
e.preventDefault();
}
}

function openHelpModal() {
if (helpModal) {
helpModalTriggerEl = document.activeElement;
helpModal.classList.add('open');
helpModal.querySelector('.close-btn')?.focus();
document.addEventListener('keydown', trapHelpModalFocus);
}
}

function closeHelpModal() {
if (helpModal) {
helpModal.classList.remove('open');
document.removeEventListener('keydown', trapHelpModalFocus);
helpModalTriggerEl?.focus();
helpModalTriggerEl = null;
}
}

Expand All @@ -5326,30 +5359,46 @@
helpBtn.addEventListener('click', openHelpModal);
}

document.addEventListener('keydown', (e) => {

Check failure on line 5362 in index.html

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this function to reduce its Cognitive Complexity from 21 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=S3DFX-CYBER_GSoC-Org-Finder-&issues=AZ8tAayo_PZEko8307ip&open=AZ8tAayo_PZEko8307ip&pullRequest=1992
const active = document.activeElement;
const isTyping = active && (
['INPUT', 'TEXTAREA', 'SELECT'].includes(active.tagName) ||
active.id === 'searchInput'
);

const helpModalOpen =
document.getElementById('helpModal')?.classList.contains('open');
const orgModalOpen =
document.getElementById('orgModal')?.classList.contains('open');
const proposalModalOpen =
document.getElementById('proposalModal')?.classList.contains('open');
Comment on lines +5369 to +5374

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Modal guard misses overlays This guard only treats the help, org, and proposal dialogs as modal state. Other overlays handled by the page, such as the compare modal, are not included, so ?, /, or Alt+1/2 can still open help, move focus to the page search, or scroll the background while that modal is open. Use one shared open-modal check for every overlay that should suppress page-level shortcuts.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

const anyModalOpen = helpModalOpen || orgModalOpen || proposalModalOpen;
// Focus search bar β€” works alongside Ctrl/Cmd but not while already typing or a modal is open
if (!anyModalOpen && !isTyping && (e.key === '/' || ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k'))) {
e.preventDefault();
document.getElementById('hero-search')?.focus();
return;
}
// Jump to Timeline section
if (!anyModalOpen && !isTyping && e.altKey && e.key === '1') {
e.preventDefault();
document.getElementById('timeline')?.scrollIntoView({ behavior: 'smooth', block: 'start' });
return;
}
// Jump to Organizations section
if (!anyModalOpen && !isTyping && e.altKey && e.key === '2') {
e.preventDefault();
document.getElementById('orgs')?.scrollIntoView({ behavior: 'smooth', block: 'start' });
return;
}

if (e.ctrlKey || e.metaKey || e.altKey) {
return;
}
const active = document.activeElement;
if (
active &&
(
['INPUT', 'TEXTAREA', 'SELECT'].includes(active.tagName) ||
active.id === 'searchInput'
)
) {
if (isTyping) {
Comment on lines +5363 to +5398

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ“ Maintainability & Code Quality | 🟠 Major | ⚑ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check for duplicate keydown listeners across index.html and app.js
rg -n "addEventListener\('keydown'|onkeydown" index.html src/js/app.js

Repository: S3DFX-CYBER/GSoC-Org-Finder-

Length of output: 1193


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the global keydown handler and the inline handler around the relevant lines.
sed -n '720,750p' src/js/app.js
printf '\n--- index.html ---\n'
sed -n '5338,5375p' index.html

Repository: S3DFX-CYBER/GSoC-Org-Finder-

Length of output: 2207


Consolidate the global keydown shortcut handler

This inline document.addEventListener('keydown', …) duplicates src/js/app.js#handleGlobalKeydown, and its isTyping guard still checks active.id === 'searchInput' while the search field is now #hero-search. Keep the shortcut logic in one place to avoid divergence.

🧰 Tools
πŸͺ› ast-grep (0.44.0)

[warning] 5341-5344: Avoid SQL injections
Context: active && (
['INPUT', 'TEXTAREA', 'SELECT'].includes(active.tagName) ||
active.id === 'searchInput'
)
Note: [CWE-89] Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection'). Security best practice.

(variable-sql-statement-injection)


[warning] 5342-5343: Avoid SQL injections
Context: ['INPUT', 'TEXTAREA', 'SELECT'].includes(active.tagName) ||
active.id === 'searchInput'
Note: [CWE-89] Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection'). Security best practice.

(variable-sql-statement-injection)

πŸ€– Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@index.html` around lines 5341 - 5369, The global keydown shortcut logic is
duplicated here and in handleGlobalKeydown, so keep the shortcut handling in one
place and remove this inline copy. Update the typing guard to match the current
search field id used by the page (`#hero-search`) instead of checking searchInput.
Use the existing handleGlobalKeydown function as the single source of truth for
shortcuts and typing-state checks.

return;
}
const helpModalOpen =
document.getElementById('helpModal')?.classList.contains('open');

const orgModalOpen =
document.getElementById('orgModal')?.classList.contains('open');

const proposalModalOpen =
document.getElementById('proposalModal')?.classList.contains('open');

if (helpModalOpen || orgModalOpen || proposalModalOpen) {
if (anyModalOpen && e.key !== 'Escape') {
return;
}

Expand Down
23 changes: 19 additions & 4 deletions src/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -664,7 +664,7 @@

// Global keydown helper functions to manage Cognitive Complexity
function handleEscapeKey(e) {
const activeModal = document.querySelector('.modal-bg.open, #mobileMenu:not(.hidden), .modal-bg.compare-bg.open');
const activeModal = document.querySelector('.modal-bg.open, #mobileMenu:not(.hidden), .modal-bg.compare-bg.open, #proposalModal.open, #proposalModal[open]');
if (activeModal) {
e.preventDefault();
closeModalElement(activeModal.id);
Expand Down Expand Up @@ -713,20 +713,35 @@
updateCardFocus();
}

function handleGlobalKeydown(e) {

Check failure on line 716 in src/js/app.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this function to reduce its Cognitive Complexity from 21 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=S3DFX-CYBER_GSoC-Org-Finder-&issues=AZ8tAaoN_PZEko8307in&open=AZ8tAaoN_PZEko8307in&pullRequest=1992
if (e.key === 'Escape' && handleEscapeKey(e)) return;

Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
if (['INPUT', 'SELECT', 'TEXTAREA'].includes(document.activeElement?.tagName)) return;

const anyModalOpen = !!document.querySelector('.modal-bg.open, .modal-bg.compare-bg.open, #proposalModal.open, #proposalModal[open]');

Check warning on line 721 in src/js/app.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this useless assignment to variable "anyModalOpen".

See more on https://sonarcloud.io/project/issues?id=S3DFX-CYBER_GSoC-Org-Finder-&issues=AZ8ykBB3gn42AMKbVI49&open=AZ8ykBB3gn42AMKbVI49&pullRequest=1992

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The anyModalOpen guard now correctly detects the proposal modal, but the existing Arrow-key, Enter, and c key handlers later in handleGlobalKeydown are not wrapped in an !anyModalOpen check. This means page-level navigation shortcuts (e.g., cycling orgs with arrows, triggering compare with c) can still fire while a modal is open, which contradicts the intent of the modal-open guard. Consider adding an early return or wrapping those downstream handlers with the same if (!anyModalOpen) condition.

Prompt for AI agents
Check if this issue is valid β€” if so, understand the root cause and fix it. At src/js/app.js, line 721:

<comment>The `anyModalOpen` guard now correctly detects the proposal modal, but the existing Arrow-key, Enter, and `c` key handlers later in `handleGlobalKeydown` are not wrapped in an `!anyModalOpen` check. This means page-level navigation shortcuts (e.g., cycling orgs with arrows, triggering compare with `c`) can still fire while a modal is open, which contradicts the intent of the modal-open guard. Consider adding an early return or wrapping those downstream handlers with the same `if (!anyModalOpen)` condition.</comment>

<file context>
@@ -718,7 +718,7 @@ function handleGlobalKeydown(e) {
   if (['INPUT', 'SELECT', 'TEXTAREA'].includes(document.activeElement?.tagName)) return;
 
-  const anyModalOpen = !!document.querySelector('.modal-bg.open, .modal-bg.compare-bg.open');
+  const anyModalOpen = !!document.querySelector('.modal-bg.open, .modal-bg.compare-bg.open, #proposalModal.open, #proposalModal[open]');
 
   const n = filteredOrgs.length;
</file context>

const anyModalOpen = !!document.querySelector('.modal-bg.open, .modal-bg.compare-bg.open, #proposalModal.open, #proposalModal[open]');

Check warning on line 722 in src/js/app.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'anyModalOpen' is already defined.

See more on https://sonarcloud.io/project/issues?id=S3DFX-CYBER_GSoC-Org-Finder-&issues=AZ8ykBB3gn42AMKbVI4-&open=AZ8ykBB3gn42AMKbVI4-&pullRequest=1992

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P0: There are duplicate const declarations for anyModalOpen and n inside handleGlobalKeydown, which causes a SyntaxError: Identifier has already been declared and prevents the script from loading. The duplicate added lines should be removed, keeping the original declarations and restoring proper indentation.

Prompt for AI agents
Check if this issue is valid β€” if so, understand the root cause and fix it. At src/js/app.js, line 722:

<comment>There are duplicate `const` declarations for `anyModalOpen` and `n` inside `handleGlobalKeydown`, which causes a `SyntaxError: Identifier has already been declared` and prevents the script from loading. The duplicate added lines should be removed, keeping the original declarations and restoring proper indentation.</comment>

<file context>
@@ -719,7 +719,10 @@ function handleGlobalKeydown(e) {
   if (['INPUT', 'SELECT', 'TEXTAREA'].includes(document.activeElement?.tagName)) return;
 
   const anyModalOpen = !!document.querySelector('.modal-bg.open, .modal-bg.compare-bg.open, #proposalModal.open, #proposalModal[open]');
+  const anyModalOpen = !!document.querySelector('.modal-bg.open, .modal-bg.compare-bg.open, #proposalModal.open, #proposalModal[open]');
+if (anyModalOpen) return;
 
</file context>

if (anyModalOpen) return;

const n = filteredOrgs.length;

Check warning on line 725 in src/js/app.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this useless assignment to variable "n".

See more on https://sonarcloud.io/project/issues?id=S3DFX-CYBER_GSoC-Org-Finder-&issues=AZ8ykBB3gn42AMKbVI4_&open=AZ8ykBB3gn42AMKbVI4_&pullRequest=1992
const n = filteredOrgs.length;

Check warning on line 726 in src/js/app.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'n' is already defined.

See more on https://sonarcloud.io/project/issues?id=S3DFX-CYBER_GSoC-Org-Finder-&issues=AZ8ykBB3gn42AMKbVI5A&open=AZ8ykBB3gn42AMKbVI5A&pullRequest=1992
Comment thread
greptile-apps[bot] marked this conversation as resolved.
Comment on lines +721 to 726

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P0 Duplicate const declarations The modal guard declares anyModalOpen twice, and the same block also declares n twice. Browsers reject duplicate const declarations in one scope, so loading this file can fail with a syntax error before the keyboard handlers register. That means the modal shortcut guard added here never runs.

Suggested change
const anyModalOpen = !!document.querySelector('.modal-bg.open, .modal-bg.compare-bg.open, #proposalModal.open, #proposalModal[open]');
const anyModalOpen = !!document.querySelector('.modal-bg.open, .modal-bg.compare-bg.open, #proposalModal.open, #proposalModal[open]');
if (anyModalOpen) return;
const n = filteredOrgs.length;
const n = filteredOrgs.length;
const anyModalOpen = !!document.querySelector('.modal-bg.open, .modal-bg.compare-bg.open, #proposalModal.open, #proposalModal[open]');
if (anyModalOpen) return;
const n = filteredOrgs.length;

if (e.key === '?') {
if (!anyModalOpen && e.key === '?') {
e.preventDefault();
openModalElement('helpModal');
return;
}
if (e.key === '/') {
if (!anyModalOpen && (e.key === '/' || ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k'))) {
e.preventDefault();
document.getElementById('hero-search')?.focus();
return;
}
if (!anyModalOpen && e.altKey && e.key === '1') {
e.preventDefault();
document.getElementById('timeline')?.scrollIntoView({ behavior: 'smooth', block: 'start' });
return;
}
if (!anyModalOpen && e.altKey && e.key === '2') {
e.preventDefault();
document.getElementById('searchInput')?.focus();
document.getElementById('orgs')?.scrollIntoView({ behavior: 'smooth', block: 'start' });
return;
}

Expand Down
Loading