Skip to content

Conversation

@jeff-matthews
Copy link
Contributor

@jeff-matthews jeff-matthews commented Dec 31, 2025

Purpose

This pull request (PR) adds a custom React component to enhance the glossary navigation experience.

Note

I used GitHub Copilot to create this and went through a few refactors to simplify the implementation as much as possible and optimize performance. CodeRabbit also suggested a refactor to align with React best practices. It would be great if a frontend developer could take a look.

This required glossary-specific CSS to support the new navigation and filtered views in both light and dark mode.

Screenshot 2025-12-31 at 5 08 12 PM

Staging

https://specterops-bp-2210-glossary-nav.mintlify.app/resources/glossary/overview

Testing

  1. Check out this branch locally
  2. Open the docs/resources/glossary/overview.mdx file
  3. Add a new term to the file (must begin with H2)
    • New term under an existing letter
    • New term under a new letter
  4. Build locally
  5. Verify that the new terms appear as expected in the filtered and unfiltered views

@jeff-matthews jeff-matthews self-assigned this Dec 31, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 31, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Adds a new glossary navigation UI that scans H2 headings to build an alphabetic filter, integrates that component into the glossary overview page, and introduces CSS rules and variables to support filtering and theming.

Changes

Cohort / File(s) Summary
Glossary documentation
docs/resources/glossary/overview.mdx
Front matter set to mode: wide; imported and rendered GlossaryNav; replaced a BloodHound-specific Tenant sentence with a generic Enterprise-instance description.
New navigation component
docs/snippets/components/glossary-nav.jsx
Added export const GlossaryNav = () => { ... }: scans document H2s, derives sorted first letters, renders sticky letter buttons (All + letters), toggles glossary-filtered and data-active-letter on content, debounced MutationObserver to rescan, cleans timers/observers on unmount, scrolls to top on filter change.
Styling / theme
docs/style.css
Added --glossary-nav-bg in :root and .dark; added glossary-filtering rules that hide all terms when .glossary-filtered is set and reveal sections via data-active-letter + .glossary-letter-<Letter> selectors; includes grouped selectors affecting H2 and their sibling sections.

Sequence Diagram

sequenceDiagram
    autonumber
    participant User
    participant GlossaryNav as GlossaryNav (React)
    participant Main as MainContent (DOM)
    participant Observer as MutationObserver

    Note over GlossaryNav,Main: Mount / Initialization
    User->>GlossaryNav: page load / mount
    GlossaryNav->>Main: querySelectorAll(h2)
    Main-->>GlossaryNav: list of H2 elements & text
    GlossaryNav->>GlossaryNav: compute letters, add data/classes
    GlossaryNav->>Observer: attach debounced observer to main content

    alt User selects a letter
        User->>GlossaryNav: click letter button
        GlossaryNav->>Main: set `.glossary-filtered` and `data-active-letter`
        Main-->>User: DOM updates to show matching sections
        GlossaryNav->>GlossaryNav: scroll to top
    end

    alt DOM changes (content added/edited)
        Observer->>GlossaryNav: mutation observed (debounced)
        GlossaryNav->>Main: rescan H2s and recompute letters
        GlossaryNav->>GlossaryNav: update UI state
    end

    User->>GlossaryNav: component unmount
    GlossaryNav->>Observer: disconnect & clear timers
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 I hopped through headings, letters all in line,
A sticky bar to pick A, B, C, or M,
I watch with gentle debounce, tidy and fine,
Reveal the sections, then hop back again—
A gloss of letters, quick as a gem!

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: introduction of a glossary navigation component (GlossaryNav). It directly relates to the primary functionality added across all modified files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@jeff-matthews jeff-matthews added the enhancement New feature or request label Dec 31, 2025
@jeff-matthews
Copy link
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 31, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
docs/snippets/components/glossary-nav.jsx (3)

40-50: Consider whether MutationObserver is necessary.

If the glossary content is static after initial page load, the MutationObserver may be unnecessary and could be removed to simplify the component. If dynamic content updates are expected, the current implementation with debouncing is reasonable.


114-114: Reduce the z-index value.

A z-index of 9999 is unnecessarily high and could cause stacking context issues. Consider using a more reasonable value like 10 or 100, which should be sufficient for a sticky navigation component.

🔎 Suggested change
-        zIndex: 9999,
+        zIndex: 100,

127-148: Add explicit type="button" to button elements.

For better accessibility and to prevent unintended form submission behavior, explicitly set type="button" on all button elements.

🔎 Suggested change
       <button
+        type="button"
         onClick={() => setActiveFilter(null)}
         style={{
         <button
+          type="button"
           key={letter}
           onClick={() => handleLetterClick(letter)}
           style={{

Also applies to: 150-174

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 76083f6 and af29fb5.

📒 Files selected for processing (3)
  • docs/resources/glossary/overview.mdx
  • docs/snippets/components/glossary-nav.jsx
  • docs/style.css
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-10-02T18:01:39.059Z
Learnt from: StephenHinck
Repo: SpecterOps/bloodhound-docs PR: 67
File: docs/collect-data/enterprise-collection/privileged-collection.mdx:7-7
Timestamp: 2025-10-02T18:01:39.059Z
Learning: In the BloodHound documentation repository, "BloodHound" as a standalone name refers to the entire product family and is appropriate to use when content applies to all products in the family (Enterprise and Community Edition). "BloodHound Enterprise" should be used only when referring specifically to Enterprise-only features or capabilities.

Applied to files:

  • docs/resources/glossary/overview.mdx
📚 Learning: 2025-08-22T22:40:24.105Z
Learnt from: StephenHinck
Repo: SpecterOps/bloodhound-docs PR: 53
File: docs/analyze-data/posture-page.mdx:33-41
Timestamp: 2025-08-22T22:40:24.105Z
Learning: BloodHound Enterprise has exactly four severity levels for attack paths: CRITICAL (95%–100%), HIGH (80%–94%), MODERATE (40%–79%), and LOW (0%–39%). There is no "NONE" or similar severity level for 0% exposure.

Applied to files:

  • docs/resources/glossary/overview.mdx
🔇 Additional comments (3)
docs/style.css (1)

69-69: LGTM! CSS variables for theming are well-defined.

The new --glossary-nav-bg custom properties provide appropriate background colors for both light and dark themes, supporting the glossary navigation component.

Also applies to: 74-74

docs/resources/glossary/overview.mdx (2)

7-7: LGTM! Clean integration of the navigation component.

The import path and component usage are straightforward. The component is appropriately placed at the top of the glossary content.

Also applies to: 11-11


4-4: Verify mode: wide is the intended layout.

The mode: wide frontmatter property has been added. Ensure this is the desired layout mode for the glossary page and that it provides adequate space for the navigation component.

@jeff-matthews
Copy link
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 31, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (4)
docs/style.css (1)

82-113: Consider using attribute selectors to reduce repetition.

The 26 explicit class selectors (one per letter) are functional but highly repetitive. Consider using attribute selectors for more maintainable CSS:

/* Instead of 26 separate rules, use: */
.glossary-filtered .glossary-term[data-glossary-letter] {
  display: block !important;
}

However, if the explicit class approach is preferred for specificity or performance reasons, the current implementation works correctly.

docs/snippets/components/glossary-nav.jsx (3)

50-50: Extract magic numbers into named constants.

The timing values (100ms initial delay, 300ms debounce) would be clearer as named constants at the top of the component.

const SETUP_DELAY_MS = 100;
const DEBOUNCE_DELAY_MS = 300;

Also applies to: 55-55


93-93: Consider scrolling to the filtered content instead of page top.

Scrolling to the top on every filter change might be jarring. Consider scrolling to the first H2 matching the selected letter for better UX.

Alternative approach
const firstTerm = document.querySelector(`.glossary-letter-${letter}`);
if (firstTerm) {
  firstTerm.scrollIntoView({ behavior: 'smooth', block: 'start' });
}

129-134: Inconsistent ternary operator formatting.

The ternary operators for fontWeight and textDecoration are formatted differently than the color ternary above them. Consider aligning the formatting for consistency.

Also applies to: 153-158

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between af29fb5 and dab29e6.

📒 Files selected for processing (2)
  • docs/snippets/components/glossary-nav.jsx
  • docs/style.css
🔇 Additional comments (3)
docs/style.css (1)

69-69: LGTM! Theme-aware custom properties added correctly.

The new --glossary-nav-bg variables provide appropriate background colors for both light and dark modes, maintaining visual consistency with the theming system.

Also applies to: 74-74

docs/snippets/components/glossary-nav.jsx (2)

20-20: Regex only matches ASCII letters.

The pattern /[A-Z]/i excludes glossary terms starting with accented or international characters (e.g., "École," "Überblick"). Consider whether this is intentional for your content.

If international terms should be supported, consider using Unicode property escapes:

const match = termName.match(/\p{L}/u);

112-112: The rgb() syntax errors from the previous review have been fixed.

All rgb(var(...)) function calls now have proper closing parentheses. The color declarations are syntactically correct.

Also applies to: 124-125, 148-149

@jeff-matthews
Copy link
Contributor Author

After polling the team, I'm going to close this for now. There's a preference for the existing navigation experience on the right that shows all terms.

If the glossary grows larger over time, letter-based navigation/filtering may be useful and we can revisit this approach.

@jeff-matthews jeff-matthews deleted the BP-2210-glossary-nav branch January 5, 2026 20:13
@github-actions github-actions bot locked and limited conversation to collaborators Jan 5, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants